Merge remote-tracking branch 'upstream/master'

This commit is contained in:
David Salz 2020-01-22 12:32:36 +01:00
commit e4053e9b2a
355 changed files with 45181 additions and 80323 deletions

3
.gitignore vendored
View File

@ -73,4 +73,5 @@ mscorlib.dll
packages
Generator/bin
*.XML
.vs
.vs
Facepunch.Steamworks.Test/bin/**

5
CompileFix.bat Normal file
View File

@ -0,0 +1,5 @@
cd Facepunch.Steamworks
dotnet restore .\Facepunch.Steamworks.Posix32.csproj
dotnet restore .\Facepunch.Steamworks.Posix64.csproj
dotnet restore .\Facepunch.Steamworks.Win32.csproj
dotnet restore .\Facepunch.Steamworks.Win64.csproj

View File

@ -0,0 +1,114 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
[DeploymentItem( "steam_api.dll" )]
public class AppTest
{
[AssemblyInitialize]
public static void AssemblyInit( TestContext context )
{
Steamworks.SteamClient.OnCallbackException = ( e ) =>
{
Console.Error.WriteLine( e.Message );
Console.Error.WriteLine( e.StackTrace );
Assert.Fail( e.Message );
};
//
// Init Client
//
Steamworks.SteamClient.Init( 252490 );
//
// Init Server
//
var serverInit = new SteamServerInit( "rust", "Rusty Mode" )
{
GamePort = 28015,
Secure = true,
QueryPort = 28016
};
Steamworks.SteamServer.Init( 252490, serverInit );
SteamServer.LogOnAnonymous();
}
static void OnNewUrlLaunchParameters()
{
// Wow!
}
[TestMethod]
public void GameLangauge()
{
var gl = SteamApps.GameLanguage;
Assert.IsNotNull( gl );
Assert.IsTrue( gl.Length > 3 );
Console.WriteLine( $"{gl}" );
}
[TestMethod]
public void AppInstallDir()
{
var str = SteamApps.AppInstallDir();
Assert.IsNotNull( str );
Assert.IsTrue( str.Length > 3 );
Console.WriteLine( $"{str}" );
}
[TestMethod]
public void AppOwner()
{
var steamid = SteamApps.AppOwner;
Assert.IsTrue( steamid.Value > 70561197960279927 );
Assert.IsTrue( steamid.Value < 80561197960279927 );
Console.WriteLine( $"{steamid.Value}" );
}
[TestMethod]
public void InstalledDepots()
{
var depots = SteamApps.InstalledDepots().ToArray();
Assert.IsNotNull( depots );
Assert.IsTrue( depots.Length > 0 );
foreach ( var depot in depots )
{
Console.WriteLine( $"{depot.Value}" );
}
}
[TestMethod]
public async Task GetFileDetails()
{
var fileinfo = await SteamApps.GetFileDetailsAsync( "hl2.exe" );
Console.WriteLine( $"fileinfo.SizeInBytes: {fileinfo?.SizeInBytes}" );
Console.WriteLine( $"fileinfo.Sha1: {fileinfo?.Sha1}" );
Console.WriteLine( $"fileinfo.Flags: {fileinfo?.Flags}" );
}
[TestMethod]
public void CommandLine()
{
var cl = SteamApps.CommandLine;
Console.WriteLine( $"CommandLine: {cl}" );
}
}
}

View File

@ -1,93 +0,0 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class Achievements
{
[TestMethod]
public void GetCount()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var gotStats = false;
client.Achievements.OnUpdated += () => { gotStats = true; };
while ( !gotStats )
{
client.Update();
}
Console.WriteLine( "Found " + client.Achievements.All.Length + " Achievements" );
Assert.AreNotEqual( 0, client.Achievements.All.Length );
}
}
[TestMethod]
public void GetNames()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var gotStats = false;
client.Achievements.OnUpdated += () => { gotStats = true; };
while ( !gotStats )
{
client.Update();
}
foreach( var ach in client.Achievements.All )
{
Assert.IsNotNull( ach.Id );
Console.WriteLine( " " + ach.Id );
Console.WriteLine( " - - " + ach.Name );
Console.WriteLine( " - - " + ach.Description );
Console.WriteLine( " - - " + ach.State );
Console.WriteLine( " - - " + ach.UnlockTime );
Console.WriteLine( " - - " + ach.GlobalUnlockedPercentage );
if ( ach.Icon != null )
{
Console.WriteLine( " - - " + ach.Icon.Width + " x " + ach.Icon.Height );
}
Console.WriteLine( "" );
}
}
}
[TestMethod]
public void Trigger()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var gotStats = false;
client.Achievements.OnUpdated += () => { gotStats = true; };
while ( !gotStats )
{
client.Update();
}
foreach ( var ach in client.Achievements.All )
{
ach.Trigger();
}
}
}
}
}

View File

@ -1,65 +0,0 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class App
{
[TestMethod]
public void IsSubscribed()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Console.WriteLine("This test assumes you own Garry's Mod and not Charles III of Spain and the antiquity");
Assert.IsTrue( client.App.IsSubscribed( 4000 ) );
Assert.IsFalse( client.App.IsSubscribed( 590440 ));
}
}
[TestMethod]
public void IsInstalled()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Console.WriteLine("This test assumes you have Garry's Mod installed but not Charles III of Spain and the antiquity");
Assert.IsTrue(client.App.IsInstalled(4000));
Assert.IsFalse(client.App.IsInstalled(590440));
}
}
[TestMethod]
public void PurchaseTime()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Console.WriteLine("This test assumes you own Garry's Mod but not Charles III of Spain and the antiquity");
var gmodBuyTime = client.App.PurchaseTime( 4000 );
Assert.AreNotEqual( gmodBuyTime, DateTime.MinValue );
Console.WriteLine($"You bought Garry's Mod {gmodBuyTime}");
var otherBuyTime = client.App.PurchaseTime(590440);
Assert.AreEqual(otherBuyTime, DateTime.MinValue);
}
}
[TestMethod]
public void AppName()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var name = client.App.GetName( 4000 );
Console.WriteLine( name );
}
}
}
}

View File

@ -1,187 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public partial class Client
{
[TestMethod]
public void Init()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
}
}
[TestMethod]
public void Init_10()
{
for ( int i = 0; i < 10; i++ )
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
}
GC.Collect();
}
}
[TestMethod]
public void Name()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var username = client.Username;
Console.WriteLine( username );
Assert.IsNotNull( username );
}
}
[TestMethod]
public void SteamId()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var steamid = client.SteamId;
Console.WriteLine( steamid );
Assert.AreNotEqual( 0, steamid );
}
}
[TestMethod]
public void AuthSessionTicket()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var ticket = client.Auth.GetAuthSessionTicket();
Assert.IsTrue( ticket != null );
Assert.IsTrue( ticket.Handle != 0 );
Assert.IsTrue( ticket.Data.Length > 0 );
ticket.Cancel();
Assert.IsTrue( ticket.Handle == 0 );
}
}
[TestMethod]
public void Update()
{
var sw = new Stopwatch();
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue(client.IsValid);
for( int i=0; i<1024; i++ )
{
sw.Restart();
client.Update();
Console.WriteLine( $"{sw.Elapsed.TotalMilliseconds}ms" );
}
}
}
[TestMethod]
public void Subscribed()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsTrue(client.IsSubscribed);
}
}
[TestMethod]
public void Owner()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.AreEqual(client.OwnerSteamId, client.SteamId);
}
}
[TestMethod]
public void InstallFolder()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsTrue(client.InstallFolder.Exists);
Console.Write($"Install Folder: {client.InstallFolder}");
}
}
[TestMethod]
public void CurrentLanguage()
{
var sw = new Stopwatch();
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
Assert.IsTrue( client.CurrentLanguage != null );
Assert.IsTrue( client.CurrentLanguage.Length > 0 );
Console.Write( $"CurrentLanguage: {client.CurrentLanguage}" );
}
}
[TestMethod]
public void AvailableLanguages()
{
var sw = new Stopwatch();
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
Assert.IsTrue( client.AvailableLanguages != null );
Assert.IsTrue( client.AvailableLanguages.Length > 0 );
foreach ( var lang in client.AvailableLanguages )
{
Console.Write( $"AvailableLanguages: {lang}" );
}
}
}
[TestMethod]
public void Cybercafe()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsFalse(client.IsCybercafe);
}
}
[TestMethod]
public void LowViolence()
{
var sw = new Stopwatch();
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
Assert.IsFalse(client.IsLowViolence);
}
}
}
}

View File

@ -1,124 +0,0 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class Friends
{
[TestMethod]
public void FriendList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
client.Friends.Refresh();
Assert.IsNotNull( client.Friends.All );
foreach ( var friend in client.Friends.All )
{
Console.WriteLine( "{0}: {1} (Friend:{2}) (Blocked:{3})", friend.Id, friend.Name, friend.IsFriend, friend.IsBlocked );
Assert.IsNotNull(friend.GetAvatar( Steamworks.Friends.AvatarSize.Medium ));
}
}
}
[TestMethod]
public void FriendListWithoutRefresh()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
foreach ( var friend in client.Friends.All )
{
Console.WriteLine( "{0}: {1} (Friend:{2}) (Blocked:{3})", friend.Id, friend.Name, friend.IsFriend, friend.IsBlocked );
}
}
}
[TestMethod]
public void Avatar()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
ulong id = (ulong)( 76561197960279927 + (new Random().Next() % 10000));
bool passed = false;
client.Friends.GetAvatar( Steamworks.Friends.AvatarSize.Medium, id, ( avatar) =>
{
if ( avatar == null )
{
Console.WriteLine( "No Avatar" );
}
else
{
Assert.AreEqual( avatar.Width, 64 );
Assert.AreEqual( avatar.Height, 64 );
Assert.AreEqual( avatar.Data.Length, avatar.Width * avatar.Height * 4 );
DrawImage( avatar );
}
passed = true;
});
while (passed == false )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
}
}
[TestMethod]
public void CachedAvatar()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
var friend = client.Friends.All.First();
var image = client.Friends.GetCachedAvatar( Steamworks.Friends.AvatarSize.Medium, friend.Id );
if (image != null)
{
Assert.AreEqual(image.Width, 64);
Assert.AreEqual(image.Height, 64);
Assert.AreEqual(image.Data.Length, image.Width * image.Height * 4);
}
}
}
public static void DrawImage( Image img )
{
var grad = " -:+#";
for ( int y = 0; y<img.Height; y++ )
{
var str = "";
for ( int x = 0; x < img.Width; x++ )
{
var p = img.GetPixel( x, y );
var brightness = 1 - ((float)(p.r + p.g + p.b) / (255.0f * 3.0f));
var c = (int) ((grad.Length) * brightness);
if ( c > 3 ) c = 3;
str += grad[c];
}
Console.WriteLine( str );
}
}
}
}

View File

@ -1,295 +0,0 @@
using System;
using System.Diagnostics;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class Inventory
{
[TestMethod]
public void InventoryDefinitions()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.IsNotNull( client.Inventory.Definitions );
Assert.AreNotEqual( 0, client.Inventory.Definitions.Length );
foreach ( var i in client.Inventory.Definitions.Where( x => x.PriceCategory != "" ) )
{
Console.WriteLine( "{0}: {1} ({2})", i.Id, i.Name, i.Type );
Console.WriteLine( " itemshortname: {0}", i.GetStringProperty( "itemshortname" ) );
Console.WriteLine( " workshopdownload: {0}", i.GetStringProperty( "workshopdownload" ) );
Console.WriteLine( " IconUrl: {0}", i.IconUrl );
Console.WriteLine( " IconLargeUrl: {0}", i.IconLargeUrl );
Console.WriteLine( " PriceRaw: {0}", i.PriceCategory );
Console.WriteLine( " PriceDollars: {0}", i.PriceDollars );
}
}
}
[TestMethod]
public void InventoryDefinitionExchange()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.IsNotNull( client.Inventory.Definitions );
Assert.AreNotEqual( 0, client.Inventory.Definitions.Length );
foreach ( var i in client.Inventory.Definitions )
{
if ( i.Recipes == null ) continue;
Console.WriteLine( "Ways To Create " + i.Name );
foreach ( var r in i.Recipes )
{
Console.WriteLine( " " + string.Join( ", ", r.Ingredients.Select( x => x.Count + " x " + x.Definition.Name ) ) );
}
}
}
}
[TestMethod]
public void InventoryDefinitionIngredients()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.IsNotNull( client.Inventory.Definitions );
Assert.AreNotEqual( 0, client.Inventory.Definitions.Length );
foreach ( var i in client.Inventory.Definitions )
{
if ( i.IngredientFor == null ) continue;
Console.WriteLine( i.Name + " Can Be Used to Make" );
foreach ( var r in i.IngredientFor )
{
Console.WriteLine( " " + r.Result.Name );
}
}
}
}
[TestMethod]
public void InventoryItemList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
bool CallbackCalled = false;
// OnUpdate hsould be called when we receive a list of our items
client.Inventory.OnUpdate = () => { CallbackCalled = true; };
// tell steam to download the items
client.Inventory.Refresh();
// Wait for the items
var timeout = Stopwatch.StartNew();
while ( client.Inventory.Items == null )
{
client.Update();
System.Threading.Thread.Sleep( 1000 );
if ( timeout.Elapsed.TotalSeconds > 10 )
break;
}
// make sure callback was called
Assert.IsTrue( CallbackCalled );
// Make sure items are valid
foreach ( var item in client.Inventory.Items )
{
Assert.IsNotNull( item );
Assert.IsNotNull( item.Definition );
Console.WriteLine( item.Definition.Name + " - " + item.Id );
}
}
}
[TestMethod]
public void InventoryItemProperties()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
while ( true )
{
client.Update();
if (client.Inventory.Items == null) continue;
foreach (var item in client.Inventory.Items)
{
Console.WriteLine($"{item.Id} ({item.Definition.Name})");
foreach (var property in item.Properties)
{
Console.WriteLine($" {property.Key} = {property.Value}");
}
Console.WriteLine("");
}
return;
}
}
}
[TestMethod]
public void Deserialize()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.IsTrue( client.IsValid );
Assert.IsNotNull(client.Inventory.Definitions);
Assert.AreNotEqual(0, client.Inventory.Definitions.Length);
client.Inventory.Refresh();
var stopwatch = Stopwatch.StartNew();
//
// Block until we have the items
//
while ( client.Inventory.SerializedItems == null )
{
client.Update();
if (stopwatch.Elapsed.Seconds > 10)
throw new System.Exception("Getting SerializedItems took too long");
}
Assert.IsNotNull( client.Inventory.SerializedItems );
Assert.IsTrue( client.Inventory.SerializedItems.Length > 4 );
using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();
Assert.IsTrue( server.IsValid );
var result = server.Inventory.Deserialize( client.Inventory.SerializedItems );
stopwatch = Stopwatch.StartNew();
while (result.IsPending)
{
server.Update();
if (stopwatch.Elapsed.Seconds > 10)
throw new System.Exception("result took too long");
}
Assert.IsFalse( result.IsPending );
Assert.IsNotNull( result.Items );
foreach ( var item in result.Items )
{
Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId );
Console.WriteLine( "Item: {0} ({1})", item.Id, item.DefinitionId );
}
}
}
}
[TestMethod]
public void PurchaseItems()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.IsNotNull(client.Inventory.Definitions);
Assert.AreNotEqual(0, client.Inventory.Definitions.Length);
while ( client.Inventory.Currency == null )
{
client.Update();
}
var shoppingList = client.Inventory.DefinitionsWithPrices.Take(2).ToArray();
bool waitingForCallback = true;
if ( !client.Inventory.StartPurchase(shoppingList, ( order, tran ) =>
{
Console.WriteLine($"Order: {order}, Transaction {tran}");
waitingForCallback = false;
} ) )
{
throw new Exception("Couldn't Buy!");
}
while ( waitingForCallback )
{
client.Update();
}
}
}
[TestMethod]
public void ListPrices()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
while ( client.Inventory.Definitions == null )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.IsNotNull(client.Inventory.Definitions);
Assert.AreNotEqual(0, client.Inventory.Definitions.Length);
while (client.Inventory.Currency == null)
{
client.Update();
}
foreach ( var i in client.Inventory.Definitions.Where( x => x.LocalPrice > 0 ) )
{
Console.WriteLine( $" {i.Name} - {i.LocalPriceFormatted} ({client.Inventory.Currency})" );
}
}
}
}
}

View File

@ -1,277 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class Leaderboard
{
[TestMethod]
public void GetLeaderboard()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
var time = Stopwatch.StartNew();
while ( !board.IsValid )
{
Thread.Sleep( 10 );
client.Update();
if (time.Elapsed.TotalSeconds > 10 )
{
throw new Exception("board.IsValid took too long");
}
}
Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
Assert.IsNotNull( board.Name );
Console.WriteLine( $"Board name is \"{board.Name}\"" );
Console.WriteLine( $"Board has \"{board.TotalEntries}\" entries" );
board.AddScore( true, 86275309, 7, 8, 9 );
board.FetchScores( Steamworks.Leaderboard.RequestType.Global, 0, 20 );
time = Stopwatch.StartNew();
while ( board.IsQuerying )
{
Thread.Sleep( 10 );
client.Update();
if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsQuerying took too long");
}
}
Assert.IsFalse( board.IsError );
Assert.IsNotNull( board.Results );
foreach ( var entry in board.Results )
{
Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({entry.Name}) with {entry.Score}" );
if ( entry.SubScores != null )
Console.WriteLine( " - " + string.Join( ";", entry.SubScores.Select( x => x.ToString() ).ToArray() ) );
}
}
}
[TestMethod]
public void GetLeaderboardCallback()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
var time = Stopwatch.StartNew();
while ( !board.IsValid )
{
Thread.Sleep( 10 );
client.Update();
if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}
Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
Assert.IsNotNull( board.Name );
board.AddScore( true, 86275309, 7, 8, 9 );
var done = false;
board.FetchScores( Steamworks.Leaderboard.RequestType.Global, 0, 20, results =>
{
foreach ( var entry in results )
{
Console.WriteLine( $"{entry.GlobalRank}: {entry.SteamId} ({entry.Name}) with {entry.Score}" );
if ( entry.SubScores != null )
Console.WriteLine( " - " + string.Join( ";", entry.SubScores.Select( x => x.ToString() ).ToArray() ) );
}
done = true;
}, error => Assert.Fail( error.ToString() ) );
while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
}
}
[TestMethod]
public void AddScores()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
var time = Stopwatch.StartNew();
while (!board.IsValid)
{
Thread.Sleep(10);
client.Update();
if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}
Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
board.AddScore( true, 1234 );
Thread.Sleep( 10 );
client.Update();
board.AddScore( true, 34566 );
Thread.Sleep( 10 );
client.Update();
board.AddScore( true, 86275309, 7, 8, 9, 7, 4, 7, 98, 24, 5, 76, 124, 6 );
Thread.Sleep( 10 );
client.Update();
board.AddScore( false, 86275309, 7, 8, 9, 7, 4, 7, 98, 24, 5, 76, 124, 6 );
Thread.Sleep( 10 );
client.Update();
}
}
[TestMethod]
public void AddScoresCallback()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
var time = Stopwatch.StartNew();
while (!board.IsValid)
{
Thread.Sleep(10);
client.Update();
if ( board.IsError )
{
throw new Exception( "Board is Error" );
}
if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}
Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
var done = false;
const int score = 5678;
board.AddScore( false, score, null, result =>
{
Assert.IsTrue( result.ScoreChanged );
Assert.AreEqual( result.Score, score );
done = true;
}, error => Assert.Fail( error.ToString() ) );
while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
}
}
[TestMethod]
public void AddFileAttachment()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
var time = Stopwatch.StartNew();
while (!board.IsValid)
{
Thread.Sleep(10);
client.Update();
if (time.Elapsed.TotalSeconds > 10)
{
throw new Exception("board.IsValid took too long");
}
}
Assert.IsTrue( board.IsValid );
Assert.IsFalse( board.IsError );
var done = false;
const int score = 5678;
const string attachment = "Hello world!";
var file = client.RemoteStorage.CreateFile( "score/example.txt" );
file.WriteAllText( attachment );
Assert.IsTrue( board.AddScore( false, score, null, result =>
{
Assert.IsTrue( result.ScoreChanged );
Assert.IsTrue( board.AttachRemoteFile( file, () =>
{
done = true;
}, error => Assert.Fail( error.ToString() ) ) );
}, error => Assert.Fail( error.ToString() ) ) );
while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
done = false;
Assert.IsTrue( board.FetchScores( Steamworks.Leaderboard.RequestType.GlobalAroundUser, 0, 0, entries =>
{
Assert.AreEqual( 1, entries.Length );
Assert.IsNotNull( entries[0].AttachedFile );
Assert.IsTrue( entries[0].AttachedFile.Download( () =>
{
Assert.AreEqual( attachment, entries[0].AttachedFile.ReadAllText() );
done = true;
}, error => Assert.Fail( error.ToString() ) ) );
}, error => Assert.Fail( error.ToString() ) ) );
while ( !done )
{
Thread.Sleep( 10 );
client.Update();
}
}
}
}
}

View File

@ -1,390 +0,0 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Facepunch.Steamworks;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem("steam_api.dll")]
[DeploymentItem("steam_api64.dll")]
public class Lobby
{
[TestMethod]
public void CreateLobby()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
Console.WriteLine($"Owner: {client.Lobby.Owner}");
Console.WriteLine($"Max Members: {client.Lobby.MaxMembers}");
Console.WriteLine($"Num Members: {client.Lobby.NumMembers}");
client.Lobby.Leave();
};
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
}
}
[TestMethod]
public void GetCreatedLobbyData()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
foreach (KeyValuePair<string, string> data in client.Lobby.CurrentLobbyData.GetAllData())
{
if (data.Key == "appid")
{
Assert.IsTrue(data.Value == "252490");
}
Console.WriteLine($"{data.Key} {data.Value}");
}
client.Lobby.Leave();
};
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
}
}
[TestMethod]
public void UpdateLobbyData()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.Name = "My Updated Lobby Name";
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
client.Lobby.LobbyType = Steamworks.Lobby.Type.Private;
client.Lobby.MaxMembers = 5;
client.Lobby.Joinable = false;
foreach (KeyValuePair<string, string> data in client.Lobby.CurrentLobbyData.GetAllData())
{
if (data.Key == "appid")
{
Assert.IsTrue(data.Value == "252490");
}
if (data.Key == "testkey")
{
Assert.IsTrue(data.Value == "testvalue");
}
if (data.Key == "lobbytype")
{
Assert.IsTrue(data.Value == Steamworks.Lobby.Type.Private.ToString());
}
Console.WriteLine($"{data.Key} {data.Value}");
}
};
client.Lobby.OnLobbyDataUpdated = () =>
{
Console.WriteLine("lobby data updated");
Console.WriteLine(client.Lobby.MaxMembers);
Console.WriteLine(client.Lobby.Joinable);
};
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
client.Lobby.Leave();
}
}
[TestMethod]
public void RefreshLobbyList()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.LobbyList.Refresh();
};
client.LobbyList.OnLobbiesUpdated = () =>
{
Console.WriteLine("lobbies updating");
if (client.LobbyList.Finished)
{
Console.WriteLine("lobbies finished updating");
Console.WriteLine($"found {client.LobbyList.Lobbies.Count} lobbies");
foreach (LobbyList.Lobby lobby in client.LobbyList.Lobbies)
{
Console.WriteLine($"Found Lobby: {lobby.Name}");
}
client.Lobby.Leave();
}
};
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 3)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
}
}
[TestMethod]
public void RefreshLobbyListWithFilter()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
};
client.Lobby.OnLobbyDataUpdated = () =>
{
var filter = new LobbyList.Filter();
filter.StringFilters.Add("testkey", "testvalue");
client.LobbyList.Refresh(filter);
};
client.LobbyList.OnLobbiesUpdated = () =>
{
Console.WriteLine("lobbies updating");
if (client.LobbyList.Finished)
{
Console.WriteLine("lobbies finished updating");
Console.WriteLine($"found {client.LobbyList.Lobbies.Count} lobbies");
foreach (LobbyList.Lobby lobby in client.LobbyList.Lobbies)
{
Console.WriteLine($"Found Lobby: {lobby.Name}");
}
}
};
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
client.Lobby.Leave();
}
}
[TestMethod]
public void RefreshLobbyListWithFilterAndGetLobbyDataFromListLobby()
{
using (var client = new Facepunch.Steamworks.Client(755870))
{
Assert.IsTrue(client.IsValid);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
};
client.Lobby.OnLobbyDataUpdated = () =>
{
var filter = new LobbyList.Filter();
filter.StringFilters.Add("testkey", "testvalue");
client.LobbyList.Refresh(filter);
};
client.LobbyList.OnLobbiesUpdated = () =>
{
Console.WriteLine("lobbies updating");
if (client.LobbyList.Finished)
{
Console.WriteLine("lobbies finished updating");
Console.WriteLine($"found {client.LobbyList.Lobbies.Count} lobbies");
foreach (LobbyList.Lobby lobby in client.LobbyList.Lobbies)
{
foreach (var pair in lobby.GetAllData())
{
Console.WriteLine(string.Format("Key: {0,-36} Value: {1}", pair.Key, pair.Value));
}
}
}
};
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
client.Lobby.Leave();
}
}
[TestMethod]
public void SendChatMessage()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
string testString = "Hello, World";
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.CurrentLobbyData.SetData("testkey", "testvalue");
client.Lobby.SendChatMessage(testString);
};
client.Lobby.OnChatMessageRecieved = (steamID, bytes, length) =>
{
string message = Encoding.UTF8.GetString(bytes, 0, length);
Console.WriteLine("message recieved");
Assert.IsTrue(message == testString);
};
client.Lobby.OnChatStringRecieved = (steamID, message) =>
{
Console.WriteLine("message recieved");
Assert.IsTrue(message == testString);
};
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
client.Lobby.Leave();
}
}
[TestMethod]
public void SetGetUserMetadata()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
client.Lobby.OnLobbyCreated = (success) =>
{
Assert.IsTrue(success);
Assert.IsTrue(client.Lobby.IsValid);
Console.WriteLine("lobby created: " + client.Lobby.CurrentLobby);
client.Lobby.SetMemberData("testkey", "testvalue");
};
client.Lobby.OnLobbyMemberDataUpdated = (steamID) =>
{
string name = client.Friends.GetName(steamID);
Console.WriteLine(name + " updated data");
Assert.IsTrue(client.Lobby.GetMemberData(steamID, "testkey") == "testvalue");
Console.WriteLine("testkey is now: " + client.Lobby.GetMemberData(steamID, "testkey"));
};
client.Lobby.Create(Steamworks.Lobby.Type.Public, 10);
var sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 5)
{
client.Update();
System.Threading.Thread.Sleep(10);
}
client.Lobby.Leave();
}
}
}
}

View File

@ -1,115 +0,0 @@
using System;
using System.Diagnostics;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public partial class Networking
{
[TestMethod]
public void PeerToPeerSend()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var TestString = "This string will be transformed to bytes, sent over the Steam P2P network, then converted back to a string.";
var OutputReceived = false;
var data = Encoding.UTF8.GetBytes( TestString );
//
// Enable listening on this channel
//
client.Networking.SetListenChannel( 0, true );
client.Networking.OnP2PData = ( steamid, bytes, length, channel ) =>
{
var str = Encoding.UTF8.GetString( bytes, 0, length );
Assert.AreEqual( str, TestString );
Assert.AreEqual( steamid, client.SteamId );
OutputReceived = true;
Console.WriteLine( "Got: " + str );
};
client.Networking.OnIncomingConnection = ( steamid ) =>
{
Console.WriteLine( "Incoming P2P Connection: " + steamid );
return true;
};
client.Networking.OnConnectionFailed = ( steamid, error ) =>
{
Console.WriteLine( "Connection Error: " + steamid + " - " + error );
};
client.Networking.SendP2PPacket( client.SteamId, data, data.Length );
while( true )
{
Thread.Sleep( 10 );
client.Update();
if ( OutputReceived )
break;
}
}
}
[TestMethod]
public void PeerToPeerFailure()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var TestString = "This string will be transformed to bytes, sent over the Steam P2P network, then converted back to a string.";
var TimeoutReceived = false;
var data = Encoding.UTF8.GetBytes( TestString );
client.Networking.OnIncomingConnection = ( steamid ) =>
{
Console.WriteLine( "Incoming P2P Connection: " + steamid );
return true;
};
client.Networking.OnConnectionFailed = ( steamid, error ) =>
{
Console.WriteLine( "Connection Error: " + steamid + " - " + error );
TimeoutReceived = true;
};
ulong rand = (ulong) new Random().Next( 1024 * 16 );
// Send to an invalid, not listening steamid
if ( !client.Networking.SendP2PPacket( client.SteamId + rand, data, data.Length ) )
{
Console.WriteLine( "Couldn't send packet" );
return;
}
var sw = Stopwatch.StartNew();
while ( true )
{
Thread.Sleep( 10 );
client.Update();
//
// Timout is usually around 15 seconds
//
if ( TimeoutReceived )
break;
if ( sw.Elapsed.TotalSeconds > 30 )
{
Assert.Fail( "Didn't time out" );
}
}
}
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class RemoteStorage
{
[TestMethod]
public void GetQuota()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
ulong total = client.RemoteStorage.QuotaTotal;
var available = client.RemoteStorage.QuotaRemaining;
Console.WriteLine( $"Total quota: {total} bytes" );
Console.WriteLine( $"Available: {available} bytes" );
}
}
[TestMethod]
public void WriteFile()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var file = client.RemoteStorage.CreateFile( "test.txt" );
const string text = "Hello world!";
file.WriteAllText( text );
Assert.IsTrue( file.Exists );
var read = file.ReadAllText();
Assert.AreEqual( text, read );
}
}
[TestMethod]
public void ReadText()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var text = client.RemoteStorage.ReadString( "test.txt" );
Assert.IsNotNull( text );
Assert.AreEqual( text, "Hello world!" );
}
}
[TestMethod]
public void WriteText()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var result = client.RemoteStorage.WriteString( "test.txt", "Hello world!" );
Assert.IsTrue( result );
}
}
[TestMethod]
public void WriteFiles()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
for ( var i = 0; i < 10; ++i )
{
client.RemoteStorage
.CreateFile( $"test_{i}/example.txt" )
.WriteAllText( Guid.NewGuid().ToString() );
}
Console.WriteLine( $"File count: {client.RemoteStorage.FileCount}" );
foreach ( var file in client.RemoteStorage.Files )
{
Console.WriteLine( $"- {file.FileName} ({file.SizeInBytes} bytes)" );
}
}
}
}
}

View File

@ -1,55 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class RichPresence
{
[TestMethod]
public void MissingKeyIsNull()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
var key = client.User.GetRichPresence( "Missing Key" );
Assert.IsNull( key );
}
}
[TestMethod]
public void ReadBackSetKey()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
client.User.SetRichPresence( "One", "Two" );
var value = client.User.GetRichPresence( "One" );
Assert.IsNotNull( value );
Assert.AreEqual( value, "Two" );
}
}
[TestMethod]
public void ClearingKeys()
{
using ( var client = new Steamworks.Client( 252490 ) )
{
client.User.SetRichPresence( "One", "Two" );
var value = client.User.GetRichPresence( "One" );
Assert.IsNotNull( value );
Assert.AreEqual( value, "Two" );
client.User.ClearRichPresence();
value = client.User.GetRichPresence( "One" );
Assert.IsNull( value );
}
}
}
}

View File

@ -1,154 +0,0 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[DeploymentItem( "tier0_s.dll" )]
[DeploymentItem( "vstdlib_s.dll" )]
[DeploymentItem( "steamclient.dll" )]
[DeploymentItem( "tier0_s64.dll" )]
[DeploymentItem( "vstdlib_s64.dll" )]
[DeploymentItem( "steamclient64.dll" )]
[TestClass]
public partial class Server
{
[TestMethod]
public void Init()
{
var serverInit = new ServerInit( "rust", "Rust" );
serverInit.GamePort = 28015;
serverInit.Secure = true;
serverInit.QueryPort = 28016;
using ( var server = new Facepunch.Steamworks.Server( 252490, serverInit ) )
{
server.ServerName = "My Test Server";
server.LogOnAnonymous();
Assert.IsTrue( server.IsValid );
}
}
[TestMethod]
public void PublicIp()
{
using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();
Assert.IsTrue( server.IsValid );
while ( true )
{
var ip = server.PublicIp;
if ( ip == null )
{
System.Threading.Thread.Sleep( 100 );
server.Update();
continue;
}
Assert.IsNotNull( ip );
Console.WriteLine( ip.ToString() );
break;
}
}
}
[TestMethod]
public void AuthCallback()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var ticket = client.Auth.GetAuthSessionTicket();
var ticketBinary = ticket.Data;
using ( var server = new Facepunch.Steamworks.Server( 252490, new ServerInit( "rust", "Rust" ) ) )
{
server.LogOnAnonymous();
Assert.IsTrue( server.IsValid );
var auth = server.Auth;
var Authed = false;
server.Auth.OnAuthChange = ( steamid, ownerid, status ) =>
{
Authed = status == ServerAuth.Status.OK;
Assert.AreEqual( steamid, client.SteamId );
Assert.AreEqual( steamid, ownerid );
Console.WriteLine( "steamid: {0}", steamid );
Console.WriteLine( "ownerid: {0}", ownerid );
Console.WriteLine( "status: {0}", status );
};
for ( int i = 0; i < 16; i++ )
{
System.Threading.Thread.Sleep( 10 );
GC.Collect();
server.Update();
GC.Collect();
client.Update();
GC.Collect();
}
GC.Collect();
if ( !server.Auth.StartSession( ticketBinary, client.SteamId ) )
{
Assert.Fail( "Start Session returned false" );
}
GC.Collect();
//
// Server should receive a ServerAuth.Status.OK
// message via the OnAuthChange callback
//
for ( int i = 0; i< 100; i++ )
{
GC.Collect();
System.Threading.Thread.Sleep( 100 );
GC.Collect();
server.Update();
client.Update();
if ( Authed )
break;
}
Assert.IsTrue( Authed );
//
// Client cancels ticket
//
ticket.Cancel();
//
// Server should receive a ticket cancelled message
//
for ( int i = 0; i < 100; i++ )
{
System.Threading.Thread.Sleep( 100 );
server.Update();
client.Update();
if ( !Authed )
break;
}
Assert.IsTrue( !Authed );
}
}
}
}
}

View File

@ -2,7 +2,7 @@
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
/*
namespace Facepunch.Steamworks.Test
{
public partial class Server
@ -40,3 +40,4 @@ namespace Facepunch.Steamworks.Test
}
}
*/

View File

@ -1,470 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public partial class ServerList
{
[TestMethod]
public void IpAddressConversions()
{
var ipstr = "185.38.150.40";
var ip = IPAddress.Parse( ipstr );
var ip_int = Facepunch.Steamworks.Utility.IpToInt32( ip );
var ip_back = Facepunch.Steamworks.Utility.Int32ToIp( ip_int );
Console.WriteLine( "ipstr: " + ipstr );
Console.WriteLine( "ip: " + ip );
Console.WriteLine( "ip int: " + ip_int );
Console.WriteLine( "ip_back: " + ip_back );
}
[TestMethod]
public void InternetList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "appid", client.AppId.ToString() );
filter.Add( "gamedir", "rust" );
filter.Add( "secure", "1" );
var query = client.ServerList.Internet( filter );
for ( int i = 0; i < 1000; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 100 );
foreach ( var s in query.Responded )
{
Assert.AreEqual( s.AppId, client.AppId );
Assert.AreEqual( s.GameDir, "rust" );
}
if ( query.Finished )
break;
}
Assert.IsTrue( query.Responded.Count > 0 );
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
foreach ( var server in query.Responded.Take( 20 ) )
{
Console.WriteLine( "{0} {1}", server.Address, server.Name );
}
query.Dispose();
for ( int i = 0; i < 100; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 1 );
}
}
}
[TestMethod]
public void MultipleInternetList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var queries = new List<Facepunch.Steamworks.ServerList.Request>();
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "map", "barren" );
for ( int i = 0; i < 10; i++ )
queries.Add( client.ServerList.Internet( filter ) );
for ( int i = 0; i < 100; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 5 );
if ( queries.Any( x => x.Finished ) )
break;
}
foreach ( var query in queries )
{
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
client.Update();
query.Dispose();
client.Update();
}
}
}
[TestMethod]
public void Filters()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "map", "barren" );
var query = client.ServerList.Internet( filter );
while ( true )
{
client.Update();
System.Threading.Thread.Sleep( 2 );
if ( query.Finished )
break;
}
foreach ( var x in query.Responded )
{
Assert.AreEqual( x.Map.ToLower(), "barren" );
}
query.Dispose();
for ( int i = 0; i < 100; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 1 );
}
}
}
[TestMethod]
public void HistoryList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "appid", client.AppId.ToString() );
filter.Add( "gamedir", "rust" );
filter.Add( "secure", "1" );
var query = client.ServerList.History( filter );
while ( true )
{
client.Update();
System.Threading.Thread.Sleep( 2 );
if ( query.Finished )
break;
}
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
foreach ( var x in query.Responded )
{
Console.WriteLine( x.Map );
}
query.Dispose();
for ( int i = 0; i < 100; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 1 );
}
}
}
[TestMethod]
public void FavouriteList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "appid", client.AppId.ToString() );
filter.Add( "gamedir", "rust" );
filter.Add( "secure", "1" );
var query = client.ServerList.Favourites( filter );
while ( true )
{
client.Update();
System.Threading.Thread.Sleep( 2 );
if ( query.Finished )
break;
}
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
foreach ( var x in query.Responded )
{
Console.WriteLine( x.Map );
}
query.Dispose();
for ( int i = 0; i < 100; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 1 );
}
}
}
[TestMethod]
public void LocalList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "appid", client.AppId.ToString() );
filter.Add( "gamedir", "rust" );
filter.Add( "secure", "1" );
var query = client.ServerList.Local( filter );
while ( true )
{
client.Update();
System.Threading.Thread.Sleep( 2 );
if ( query.Finished )
break;
}
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
foreach ( var x in query.Responded )
{
Console.WriteLine( x.Map );
}
query.Dispose();
for ( int i = 0; i < 100; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 1 );
}
}
}
[TestMethod]
public void CustomList()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var servers = new List<string>();
servers.Add( "158.85.101.20:28015" );
servers.Add( "158.85.101.20:28022" );
servers.Add( "173.192.176.171:28615" );
servers.Add( "109.95.212.35:28215" );
servers.Add( "109.95.212.35:28115" );
servers.Add( "27.50.72.176:28015" );
servers.Add( "109.95.212.40:28015" );
servers.Add( "212.38.168.149:28215" );
servers.Add( "27.50.72.167:28215" );
servers.Add( "85.236.105.7:28215" );
servers.Add( "107.182.233.216:28215" );
servers.Add( "85.236.105.11:28215" );
servers.Add( "109.95.211.198:28215" );
servers.Add( "8.26.94.190:28015" );
servers.Add( "221.121.151.37:28215" );
servers.Add( "161.202.144.216:28215" );
servers.Add( "107.182.230.181:28215" );
servers.Add( "107.182.231.134:27101" );
servers.Add( "107.182.233.181:27101" );
servers.Add( "78.129.153.47:27101" );
servers.Add( "109.95.211.206:27101" );
servers.Add( "169.57.142.73:27101" );
servers.Add( "221.121.154.147:27101" );
servers.Add( "31.216.52.44:30015" );
servers.Add( "109.169.94.17:28215" );
servers.Add( "109.169.94.17:28315" );
servers.Add( "109.169.94.17:28015" );
servers.Add( "41.0.11.167:27141" );
servers.Add( "78.129.153.47:27131" );
servers.Add( "109.95.211.206:27111" );
servers.Add( "107.182.231.134:27111" );
servers.Add( "198.27.70.162:28015" );
servers.Add( "198.27.70.162:28215" );
servers.Add( "198.27.70.162:28115" );
servers.Add( "169.57.142.73:27111" );
servers.Add( "221.121.154.147:27111" );
servers.Add( "107.182.233.181:27111" );
servers.Add( "78.129.153.47:27111" );
servers.Add( "109.95.211.215:28015" );
servers.Add( "50.23.131.208:28015" );
servers.Add( "50.23.131.208:28115" );
servers.Add( "50.23.131.208:28215" );
servers.Add( "63.251.114.37:28215" );
servers.Add( "63.251.114.37:28115" );
servers.Add( "63.251.114.37:28015" );
servers.Add( "149.202.89.85:27101" );
servers.Add( "149.202.89.85:27111" );
servers.Add( "149.202.89.85:27131" );
servers.Add( "8.26.94.147:27101" );
servers.Add( "8.26.94.147:27111" );
servers.Add( "8.26.94.147:27121" );
servers.Add( "159.8.147.197:28025" );
servers.Add( "162.248.88.203:27038" );
servers.Add( "162.248.88.203:28091" );
servers.Add( "74.91.119.142:28069" );
servers.Add( "162.248.88.203:25063" );
servers.Add( "64.251.7.189:28115" );
servers.Add( "64.251.7.189:28015" );
servers.Add( "216.52.0.170:28215" );
servers.Add( "217.147.91.80:28215" );
servers.Add( "63.251.112.121:28215" );
servers.Add( "162.248.88.203:28074" );
servers.Add( "74.91.119.142:27095" );
servers.Add( "95.172.92.176:28065" );
servers.Add( "192.223.26.55:26032" );
servers.Add( "40.114.199.6:28085" );
servers.Add( "95.172.92.176:27095" );
servers.Add( "216.52.0.172:28015" );
servers.Add( "216.52.0.171:28115" );
servers.Add( "27.50.72.179:28015" );
servers.Add( "27.50.72.180:28115" );
servers.Add( "221.121.158.203:28015" );
servers.Add( "63.251.242.246:28015" );
servers.Add( "85.236.105.51:28015" );
servers.Add( "85.236.105.47:28015" );
servers.Add( "209.95.60.216:28015" );
servers.Add( "212.38.168.14:28015" );
servers.Add( "217.147.91.138:28015" );
servers.Add( "31.216.52.42:28015" );
servers.Add( "107.182.226.225:28015" );
servers.Add( "109.95.211.69:28015" );
servers.Add( "209.95.56.13:28015" );
servers.Add( "173.244.192.101:28015" );
servers.Add( "221.121.158.201:28115" );
servers.Add( "63.251.242.245:28115" );
servers.Add( "85.236.105.50:28115" );
servers.Add( "85.236.105.46:28115" );
servers.Add( "209.95.60.217:28115" );
servers.Add( "212.38.168.13:28115" );
servers.Add( "217.147.91.139:28115" );
servers.Add( "107.182.226.224:28115" );
servers.Add( "109.95.211.14:28115" );
servers.Add( "109.95.211.16:28115" );
servers.Add( "109.95.211.17:28115" );
servers.Add( "209.95.56.14:28115" );
servers.Add( "173.244.192.100:28115" );
servers.Add( "209.95.60.218:28215" );
servers.Add( "109.95.211.13:28215" );
servers.Add( "109.95.211.15:28215" );
servers.Add( "31.216.52.41:29015" );
var query = client.ServerList.Custom( servers );
for ( int i = 0; i < 1000; i++ )
{
client.Update();
System.Threading.Thread.Sleep( 20 );
if ( query.Finished )
break;
}
Console.WriteLine( "Responded: " + query.Responded.Count.ToString() );
Console.WriteLine( "Unresponsive: " + query.Unresponsive.Count.ToString() );
foreach ( var s in query.Responded )
{
Console.WriteLine( "{0} - {1}", s.Address, s.Name );
Assert.IsTrue( servers.Contains( $"{s.Address}:{s.QueryPort}" ) );
}
query.Dispose();
}
}
[TestMethod]
public void Rules()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var filter = new Facepunch.Steamworks.ServerList.Filter();
filter.Add( "appid", client.AppId.ToString() );
filter.Add( "gamedir", "rust" );
filter.Add( "secure", "1" );
filter.Add( "addr", "185.97.254.146" );
using ( var query = client.ServerList.Internet( filter ) )
{
for ( int i = 0; i < 1000; i++ )
{
GC.Collect();
client.Update();
GC.Collect();
System.Threading.Thread.Sleep( 10 );
// if ( query.Responded.Count > 20 )
// break;
if ( query.Finished )
break;
}
query.Dispose();
var servers = query.Responded.Take( 100 );
foreach ( var server in servers )
{
server.FetchRules();
int i = 0;
while ( !server.HasRules )
{
i++;
client.Update();
System.Threading.Thread.Sleep( 10 );
if ( i > 100 )
break;
}
if ( server.HasRules )
{
Console.WriteLine( "" );
Console.WriteLine( "" );
Console.WriteLine( server.Address );
Console.WriteLine( "" );
foreach ( var rule in server.Rules )
{
Console.WriteLine( rule.Key + " = " + rule.Value );
}
}
else
{
Console.WriteLine( "SERVER HAS NO RULES :(" );
}
}
}
}
}
}
}

View File

@ -1,73 +0,0 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class Stats
{
[TestMethod]
public void UpdateStats()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
client.Stats.UpdateStats();
}
}
[TestMethod]
public void UpdateSUpdateGlobalStatstats()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
client.Stats.UpdateGlobalStats( 1 );
client.Stats.UpdateGlobalStats( 3 );
client.Stats.UpdateGlobalStats( 7 );
}
}
[TestMethod]
public void GetClientFloat()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetFloat( "deaths" );
Console.WriteLine( v );
}
}
[TestMethod]
public void GetClientInt()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetInt( "deaths" );
Console.WriteLine( v );
}
}
[TestMethod]
public void GetGlobalFloat()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetGlobalFloat( "deaths" );
Console.WriteLine( v );
}
}
[TestMethod]
public void GetGlobalInt()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var v = client.Stats.GetGlobalInt( "deaths" );
Console.WriteLine( v );
}
}
}
}

View File

@ -1,124 +0,0 @@
using System;
using System.Diagnostics;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Facepunch.Steamworks.Test
{
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class Voice
{
static readonly MemoryStream decompressStream = new MemoryStream();
[TestMethod]
public void GetVoice()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
int unCompressed = 0;
int compressed = 0;
client.Voice.OnCompressedData = ( buffer, length ) =>
{
compressed += length;
if ( !client.Voice.Decompress( buffer, length, decompressStream ) )
{
Assert.Fail( "Decompress returned false" );
}
};
client.Voice.OnUncompressedData = ( buffer, length ) =>
{
unCompressed += length;
};
client.Voice.WantsRecording = true;
var sw = Stopwatch.StartNew();
while ( sw.Elapsed.TotalSeconds < 3 )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.AreNotEqual( unCompressed, 0 );
Assert.AreNotEqual( compressed, 0 );
// Should really be > 0 if the mic was getting audio
Console.WriteLine( "unCompressed: {0}", unCompressed );
Console.WriteLine( "compressed: {0}", compressed );
}
}
[TestMethod]
public void CompressedOnly()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
int compressed = 0;
client.Voice.OnCompressedData = ( buffer, length ) =>
{
compressed += length;
};
client.Voice.WantsRecording = true;
var sw = Stopwatch.StartNew();
while ( sw.Elapsed.TotalSeconds < 3 )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.AreNotEqual( compressed, 0 );
Console.WriteLine( "compressed: {0}", compressed );
}
}
[TestMethod]
public void UnCompressedOnly()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
int unCompressed = 0;
client.Voice.OnUncompressedData = ( buffer, length ) =>
{
unCompressed += length;
};
client.Voice.WantsRecording = true;
var sw = Stopwatch.StartNew();
while ( sw.Elapsed.TotalSeconds < 3 )
{
client.Update();
System.Threading.Thread.Sleep( 10 );
}
Assert.AreNotEqual( unCompressed, 0 );
// Should really be > 0 if the mic was getting audio
Console.WriteLine( "unCompressed: {0}", unCompressed );
}
}
[TestMethod]
public void OptimalSampleRate()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
var rate = client.Voice.OptimalSampleRate;
Assert.AreNotEqual( rate, 0 );
}
}
}
}

View File

@ -1,535 +0,0 @@
using System;
using System.Text;
using System.Threading;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Diagnostics;
namespace Facepunch.Steamworks.Test
{
[TestClass]
[DeploymentItem( "steam_api.dll" )]
[DeploymentItem( "steam_api64.dll" )]
public class WorkshopTest
{
[TestMethod]
public void Query()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var Query = client.Workshop.CreateQuery();
Query.Order = Workshop.Order.RankedByTrend;
Query.Run();
// Block, wait for result
// (don't do this in realtime)
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
// results
Console.WriteLine( "Searching" );
Query.Order = Workshop.Order.RankedByTextSearch;
Query.QueryType = Workshop.QueryType.MicrotransactionItems;
Query.SearchText = "black";
Query.RequireTags.Add( "LongTShirt Skin" );
Query.Run();
// Block, wait for result
// (don't do this in realtime)
Query.Block();
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
foreach ( var item in Query.Items )
{
Console.WriteLine( "{0}", item.Title );
Console.WriteLine( "\t WebsiteViews: {0}", item.WebsiteViews );
Console.WriteLine( "\t VotesUp: {0}", item.VotesUp );
Console.WriteLine( "\t PreviewUrl: {0}", item.PreviewImageUrl );
Assert.IsTrue( item.PreviewImageUrl.Contains( "http" ) );
}
}
}
[TestMethod]
public void QueryMyFiles()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var Query = client.Workshop.CreateQuery();
Query.UserId = client.SteamId;
Query.UserQueryType = Workshop.UserQueryType.Published;
Query.Run();
// Block, wait for result
// (don't do this in realtime)
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
foreach ( var item in Query.Items )
{
Console.WriteLine( "{0}", item.Title );
Console.WriteLine( "\t WebsiteViews: {0}", item.WebsiteViews );
Console.WriteLine( "\t VotesUp: {0}", item.VotesUp );
Console.WriteLine( "\t PreviewUrl: {0}", item.PreviewImageUrl );
Console.WriteLine( "\t Directory: {0}", item.Directory );
Assert.IsTrue( item.PreviewImageUrl.Contains( "http" ) );
}
}
}
[TestMethod]
public void QueryTagRequire()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.RequireTags.Add( "LongTShirt Skin" );
Query.Run();
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
foreach ( var item in Query.Items )
{
Console.WriteLine( "{0}", item.Title );
Console.WriteLine( "\t{0}", string.Join( ";", item.Tags ) );
Assert.IsTrue( item.Tags.Contains( "longtshirt skin" ) );
}
}
}
}
[TestMethod]
public void QueryTagRequireMultiple()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.RequireTags.Add( "LongTShirt Skin" );
Query.RequireTags.Add( "version2" );
Query.RequireAllTags = true;
Query.Run();
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
foreach ( var item in Query.Items )
{
Console.WriteLine( "{0}", item.Title );
Console.WriteLine( "\t{0}", string.Join( ";", item.Tags ) );
Assert.IsTrue( item.Tags.Contains( "longtshirt skin" ) );
Assert.IsTrue( item.Tags.Contains( "version2" ) );
}
}
}
}
[TestMethod]
public void QueryTagExclude()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.RequireTags.Add( "LongTShirt Skin" );
Query.ExcludeTags.Add( "version2" );
Query.Run();
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
foreach ( var item in Query.Items )
{
Console.WriteLine( "{0}", item.Title );
Console.WriteLine( "\t{0}", string.Join( ";", item.Tags ) );
Assert.IsTrue( item.Tags.Contains( "longtshirt skin" ) );
Assert.IsFalse( item.Tags.Contains( "version2" ) );
}
}
}
}
[TestMethod]
public void QueryFile()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.FileId.Add( 751993251 );
Query.Run();
Assert.IsTrue( Query.IsRunning );
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.AreEqual( Query.TotalResults, 1 );
Assert.AreEqual( Query.Items.Length, 1 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
Assert.AreEqual<ulong>( Query.Items[0].Id, 751993251 );
}
}
}
[TestMethod]
public void QueryCallback()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
var gotCallback = false;
Query.OnResult = ( q ) =>
{
Assert.AreEqual( q.Items.Length, 1 );
Console.WriteLine( "Query.TotalResults: {0}", q.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", q.Items.Length );
gotCallback = true;
};
Query.FileId.Add( 751993251 );
Query.Run();
Assert.IsTrue( Query.IsRunning );
client.UpdateWhile( () => gotCallback == false );
Assert.IsFalse( Query.IsRunning );
Assert.AreEqual( Query.TotalResults, 1 );
Assert.AreEqual<ulong>( Query.Items[0].Id, 751993251 );
}
}
}
[TestMethod]
public void QueryFiles()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.FileId.Add( 751993251 );
Query.FileId.Add( 747266909 );
Query.Run();
Assert.IsTrue( Query.IsRunning );
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.AreEqual( Query.TotalResults, 2 );
Assert.AreEqual( Query.Items.Length, 2 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
Assert.IsTrue( Query.Items.Any( x => x.Id == 751993251 ) );
Assert.IsTrue( Query.Items.Any( x => x.Id == 747266909 ) );
}
}
}
[TestMethod]
public void Query_255()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.PerPage = 255;
Query.Run();
Assert.IsTrue( Query.IsRunning );
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.AreEqual( Query.Items.Length, 255 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
}
}
}
[TestMethod]
public void Query_28()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.PerPage = 28;
Query.Run();
Query.Block();
var firstPage = Query.Items;
Assert.AreEqual( firstPage.Length, 28 );
Console.WriteLine( "Page 2" );
Query.Page++;
Query.Run();
Query.Block();
var secondPage = Query.Items;
Assert.AreEqual( secondPage.Length, 28 );
Console.WriteLine( "Page 3" );
Query.Page++;
Query.Run();
Query.Block();
var thirdPage = Query.Items;
Assert.AreEqual( thirdPage.Length, 28 );
foreach ( var i in firstPage )
{
Assert.IsFalse( secondPage.Any( x => x.Id == i.Id ) );
Assert.IsFalse( thirdPage.Any( x => x.Id == i.Id ) );
}
foreach ( var i in secondPage )
{
Assert.IsFalse( firstPage.Any( x => x.Id == i.Id ) );
Assert.IsFalse( thirdPage.Any( x => x.Id == i.Id ) );
}
foreach ( var i in thirdPage )
{
Assert.IsFalse( secondPage.Any( x => x.Id == i.Id ) );
Assert.IsFalse( firstPage.Any( x => x.Id == i.Id ) );
}
}
}
}
[TestMethod]
public void DownloadFile()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var item = client.Workshop.GetItem( 844466101 );
var time = Stopwatch.StartNew();
if ( !item.Installed )
{
item.Download();
while ( !item.Installed )
{
Thread.Sleep( 500 );
client.Update();
Console.WriteLine( "Download Progress: {0}", item.DownloadProgress );
if (time.Elapsed.Seconds > 30)
throw new Exception("item.Installed Took Too Long");
}
}
Assert.IsNotNull( item.Directory );
Assert.AreNotEqual( 0, item.Size );
Console.WriteLine( "item.Installed: {0}", item.Installed );
Console.WriteLine( "item.Downloading: {0}", item.Downloading );
Console.WriteLine( "item.DownloadPending: {0}", item.DownloadPending );
Console.WriteLine( "item.Directory: {0}", item.Directory );
Console.WriteLine( "item.Size: {0}mb", (item.Size / 1024 / 1024) );
}
}
[TestMethod]
[TestCategory( "Run Manually" )]
public void CreatePublish()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var item = client.Workshop.CreateItem( Workshop.ItemType.Microtransaction );
item.Title = "Facepunch.Steamworks Unit test";
item.Tags.Add( "Apple" );
item.Tags.Add( "Banana" );
// Make a folder
var testFolder = new System.IO.DirectoryInfo("BlahBlah");
if (!testFolder.Exists) testFolder.Create();
item.Folder = testFolder.FullName;
// Upload a file of random bytes
var rand = new Random();
var testFile = new byte[1024 * 1024 * 32];
rand.NextBytes(testFile);
System.IO.File.WriteAllBytes( testFolder.FullName + "/testfile1.bin", testFile);
Console.WriteLine(item.Folder);
try
{
item.Publish();
while ( item.Publishing )
{
client.Update();
Thread.Sleep( 10 );
Console.WriteLine("Progress: " + item.Progress);
Console.WriteLine("BytesUploaded: " + item.BytesUploaded);
Console.WriteLine("BytesTotal: " + item.BytesTotal);
}
Assert.IsFalse( item.Publishing );
Assert.AreNotEqual( 0, item.Id );
Assert.IsNull( item.Error, item.Error );
Console.WriteLine( "item.Id: {0}", item.Id );
using ( var Query = client.Workshop.CreateQuery() )
{
Query.FileId.Add( item.Id );
Query.Run();
Query.Block();
var itemInfo = Query.Items[0];
Assert.AreEqual( itemInfo.Id, item.Id );
Assert.AreEqual( itemInfo.OwnerId, client.SteamId );
Assert.AreEqual( itemInfo.Title, item.Title );
Assert.IsTrue( itemInfo.Tags.Contains( "apple" ), "Missing Tag" );
Assert.IsTrue( itemInfo.Tags.Contains( "banana" ), "Missing Tag" );
}
}
finally
{
Console.WriteLine( "Deleting: {0}", item.Id );
item.Delete();
System.IO.File.Delete(testFolder.FullName + "/testfile.bin");
}
}
}
[TestMethod]
public void UserQuery()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
var Query = client.Workshop.CreateQuery();
Query.UserId = 76561197960279927;
Query.UserQueryType = Workshop.UserQueryType.Published;
Query.Run();
// Block, wait for result
// (don't do this in realtime)
Query.Block();
Assert.IsFalse( Query.IsRunning );
Assert.IsTrue( Query.TotalResults > 0 );
Assert.IsTrue( Query.Items.Length > 0 );
Console.WriteLine( "Query.TotalResults: {0}", Query.TotalResults );
Console.WriteLine( "Query.Items.Length: {0}", Query.Items.Length );
foreach ( var item in Query.Items )
{
Console.WriteLine( "{0}", item.Title );
Assert.AreEqual<ulong>( item.OwnerId, 76561197960279927 );
}
}
}
}
}

View File

@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3F6183AD-D966-44F2-A6EB-42E61E591B49}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Facepunch.Steamworks.Test</RootNamespace>
<AssemblyName>Facepunch.Steamworks.Test</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<RootNamespace>Facepunch.Steamworks.TestWin32</RootNamespace>
<AssemblyName>Facepunch.Steamworks.TestWin32</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
@ -16,23 +17,30 @@
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DefineConstants>TRACE;DEBUG;TEST_WIN32</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x86</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<DefineConstants>TRACE;TEST_WIN32</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
@ -42,6 +50,7 @@
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
@ -51,96 +60,83 @@
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.0.0-beta4\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.0.0-beta4\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework">
<Private>False</Private>
</Reference>
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="Client\AchievementsTest.cs" />
<Compile Include="Client\ClientTest.cs" />
<Compile Include="Client\LobbyTest.cs" />
<Compile Include="Client\RichPresenceTest.cs" />
<Compile Include="Client\LeaderboardTest.cs" />
<Compile Include="Client\AppTest.cs" />
<Compile Include="Client\RemoteStorageTest.cs" />
<Compile Include="Client\VoiceTest.cs" />
<Compile Include="Client\InventoryTest.cs" />
<Compile Include="Client\WorkshopTest.cs" />
<Compile Include="Client\NetworkingTest.cs" />
<Compile Include="FriendsTest.cs" />
<Compile Include="InputTest.cs" />
<Compile Include="NetworkingSockets.cs" />
<Compile Include="SteamMatchmakingTest.cs" />
<Compile Include="RemoteStorageTest.cs" />
<Compile Include="InventoryTest.cs" />
<Compile Include="SteamNetworkingTest.cs" />
<Compile Include="UgcTest.cs" />
<Compile Include="UgcEditor.cs" />
<Compile Include="UserTest.cs" />
<Compile Include="UserStatsTest.cs" />
<Compile Include="UgcQuery.cs" />
<Compile Include="NetworkingUtils.cs" />
<Compile Include="UtilsTest.cs" />
<Compile Include="AppTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Client\FriendsTest.cs" />
<Compile Include="Client\Server\ServerTest.cs" />
<Compile Include="GameServerTest.cs" />
<Compile Include="Client\Server\StatsTest.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="Client\ServerlistTest.cs" />
<Compile Include="Client\StatsTest.cs" />
<Compile Include="ServerlistTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
<Project>{91962664-eb42-472a-94c8-c4ffeb44cc4b}</Project>
<Name>Facepunch.Steamworks</Name>
<ProjectReference Include="..\Facepunch.Steamworks\Facepunch.Steamworks.Win32.csproj">
<Project>{2d6247f6-8ab2-405f-a00e-3a364b808a55}</Project>
<Name>Facepunch.Steamworks.Win32</Name>
</ProjectReference>
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{165081E3-BD96-404B-B83E-A635F1AF7CDE}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Facepunch.Steamworks.TestWin64</RootNamespace>
<AssemblyName>Facepunch.Steamworks.TestWin64</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;TEST_WIN64</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<PlatformTarget>x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.0.0-beta4\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\MSTest.TestFramework.2.0.0-beta4\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="FriendsTest.cs" />
<Compile Include="InputTest.cs" />
<Compile Include="NetworkingSockets.cs" />
<Compile Include="SteamMatchmakingTest.cs" />
<Compile Include="RemoteStorageTest.cs" />
<Compile Include="InventoryTest.cs" />
<Compile Include="SteamNetworkingTest.cs" />
<Compile Include="UgcTest.cs" />
<Compile Include="UgcEditor.cs" />
<Compile Include="UserTest.cs" />
<Compile Include="UserStatsTest.cs" />
<Compile Include="UgcQuery.cs" />
<Compile Include="NetworkingUtils.cs" />
<Compile Include="UtilsTest.cs" />
<Compile Include="AppTest.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GameServerTest.cs" />
<Compile Include="Client\Server\StatsTest.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="ServerlistTest.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Facepunch.Steamworks\Facepunch.Steamworks.Win64.csproj">
<Project>{8c73da93-73ad-4445-9a2c-15d4a44337d3}</Project>
<Name>Facepunch.Steamworks.Win64</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.props'))" />
<Error Condition="!Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets'))" />
</Target>
<Import Project="..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.2.0.0-beta4\build\net45\MSTest.TestAdapter.targets')" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,176 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Threading.Tasks;
using Steamworks.Data;
namespace Steamworks
{
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public class FriendsTest
{
[TestMethod]
public void GetFriends()
{
foreach ( var friend in SteamFriends.GetFriends() )
{
Console.WriteLine( $"{friend.Id.Value}: {friend.Name} (Friend:{friend.IsFriend}) (Blocked:{friend.IsBlocked})" );
Console.WriteLine( $" {string.Join( ", ", friend.NameHistory )}" );
// Assert.IsNotNull( friend.GetAvatar( Steamworks.Friends.AvatarSize.Medium ) );
}
}
[TestMethod]
public void GetBlocked()
{
foreach ( var friend in SteamFriends.GetBlocked() )
{
Console.WriteLine( $"{friend.Id.Value}: {friend.Name} (Friend:{friend.IsFriend}) (Blocked:{friend.IsBlocked})" );
Console.WriteLine( $" {string.Join( ", ", friend.NameHistory )}" );
// Assert.IsNotNull( friend.GetAvatar( Steamworks.Friends.AvatarSize.Medium ) );
}
}
[TestMethod]
public async Task GetPlayedWith()
{
foreach ( var friend in SteamFriends.GetPlayedWith() )
{
await friend.RequestInfoAsync();
Console.WriteLine( $"{friend.Id.Value}: {friend.Name} (Friend:{friend.IsFriend}) (Blocked:{friend.IsBlocked})" );
Console.WriteLine( $" {string.Join( ", ", friend.NameHistory )}" );
// Assert.IsNotNull( friend.GetAvatar( Steamworks.Friends.AvatarSize.Medium ) );
}
}
[TestMethod]
public async Task LargeAvatar()
{
ulong id = (ulong)(76561197960279927 + (new Random().Next() % 10000));
var image = await SteamFriends.GetLargeAvatarAsync( id );
if ( !image.HasValue )
return;
Console.WriteLine( $"image.Width {image.Value.Width}" );
Console.WriteLine( $"image.Height {image.Value.Height}" );
DrawImage( image.Value );
}
[TestMethod]
public async Task MediumAvatar()
{
ulong id = (ulong)(76561197960279927 + (new Random().Next() % 10000));
Console.WriteLine( $"Steam: http://steamcommunity.com/profiles/{id}" );
var image = await SteamFriends.GetMediumAvatarAsync( id );
if ( !image.HasValue )
return;
Console.WriteLine( $"image.Width {image.Value.Width}" );
Console.WriteLine( $"image.Height {image.Value.Height}" );
DrawImage( image.Value );
}
[TestMethod]
public async Task SmallAvatar()
{
ulong id = (ulong)(76561197960279927 + (new Random().Next() % 10000));
var image = await SteamFriends.GetSmallAvatarAsync( id );
if ( !image.HasValue )
return;
Console.WriteLine( $"image.Width {image.Value.Width}" );
Console.WriteLine( $"image.Height {image.Value.Height}" );
DrawImage( image.Value );
}
[TestMethod]
public async Task GetFriendsAvatars()
{
foreach ( var friend in SteamFriends.GetFriends() )
{
Console.WriteLine( $"{friend.Id.Value}: {friend.Name}" );
var image = await friend.GetSmallAvatarAsync();
if ( image.HasValue )
{
DrawImage( image.Value );
}
// Assert.IsNotNull( friend.GetAvatar( Steamworks.Friends.AvatarSize.Medium ) );
}
}
/*
[TestMethod]
public void FriendListWithoutRefresh()
{
using ( var client = new Facepunch.Steamworks.Client( 252490 ) )
{
Assert.IsTrue( client.IsValid );
foreach ( var friend in client.Friends.All )
{
Console.WriteLine( "{0}: {1} (Friend:{2}) (Blocked:{3})", friend.Id, friend.Name, friend.IsFriend, friend.IsBlocked );
}
}
}
[TestMethod]
public void CachedAvatar()
{
using (var client = new Facepunch.Steamworks.Client(252490))
{
Assert.IsTrue(client.IsValid);
var friend = client.Friends.All.First();
var image = client.Friends.GetCachedAvatar( Steamworks.Friends.AvatarSize.Medium, friend.Id );
if (image != null)
{
Assert.AreEqual(image.Width, 64);
Assert.AreEqual(image.Height, 64);
Assert.AreEqual(image.Data.Length, image.Width * image.Height * 4);
}
}
}
*/
public static void DrawImage( Image img )
{
var grad = " -:+#";
for ( int y = 0; y < img.Height; y++ )
{
var str = "";
for ( int x = 0; x < img.Width; x++ )
{
var p = img.GetPixel( x, y );
var brightness = 1 - ((float)(p.r + p.g + p.b) / (255.0f * 3.0f));
var c = (int)((grad.Length) * brightness);
if ( c > 3 ) c = 3;
str += grad[c];
}
Console.WriteLine( str );
}
}
}
}

View File

@ -0,0 +1,126 @@
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Steamworks
{
[DeploymentItem( "steam_api64.dll" )]
[TestClass]
public partial class GameServerTest
{
[TestMethod]
public void Init()
{
SteamServer.DedicatedServer = true;
SteamServer.DedicatedServer = false;
}
[TestMethod]
public async Task PublicIp()
{
while ( true )
{
var ip = SteamServer.PublicIp;
if ( ip == null )
{
await Task.Delay( 10 );
continue;
}
Assert.IsNotNull( ip );
Console.WriteLine( ip.ToString() );
break;
}
}
[TestMethod]
public async Task BeginAuthSession()
{
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
bool finished = false;
string failed = null;
AuthResponse response = AuthResponse.AuthTicketInvalidAlreadyUsed;
//
// Clientside calls this function, gets ticket
//
var clientTicket = SteamUser.GetAuthSessionTicket();
//
// The client sends this data to the server along with their steamid
//
var ticketData = clientTicket.Data;
var clientSteamId = SteamClient.SteamId;
//
// Server listens to auth responses from Gabe
//
SteamServer.OnValidateAuthTicketResponse += ( steamid, ownerid, rsponse ) =>
{
finished = true;
response = rsponse;
if ( steamid == 0 )
failed = $"steamid is 0! {steamid} != {ownerid} ({rsponse})";
if ( ownerid == 0 )
failed = $"ownerid is 0! {steamid} != {ownerid} ({rsponse})";
if ( steamid != ownerid )
failed = $"Steamid and Ownerid are different! {steamid} != {ownerid} ({rsponse})";
};
//
// Server gets the ticket, starts authing
//
if ( !SteamServer.BeginAuthSession( ticketData, clientSteamId ) )
{
Assert.Fail( "BeginAuthSession returned false, called bullshit without even having to check with Gabe" );
}
//
// Wait for that to go through steam
//
while ( !finished )
{
if ( stopwatch.Elapsed.TotalSeconds > 5 )
throw new System.Exception( "Took too long waiting for AuthSessionResponse.OK" );
await Task.Delay( 10 );
}
Assert.AreEqual( response, AuthResponse.OK );
if ( failed != null )
Assert.Fail( failed );
finished = false;
stopwatch = System.Diagnostics.Stopwatch.StartNew();
//
// The client is leaving, and now wants to cancel the ticket
//
Assert.AreNotEqual( 0, clientTicket.Handle );
clientTicket.Cancel();
//
// We should get another callback
//
while ( !finished )
{
if ( stopwatch.Elapsed.TotalSeconds > 5 )
throw new System.Exception( "Took too long waiting for AuthSessionResponse.AuthTicketCanceled" );
await Task.Delay( 10 );
}
if ( failed != null )
Assert.Fail( failed );
//Assert.AreEqual( response, AuthResponse.AuthTicketCanceled );
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
[DeploymentItem( "controller_config/game_actions_252490.vdf" )]
public class InputTest
{
[TestMethod]
public void ControllerList()
{
foreach ( var controller in SteamInput.Controllers )
{
Console.Write( $"Controller: {controller}" );
var dstate = controller.GetDigitalState( "fire" );
var astate = controller.GetAnalogState( "Move" );
}
}
}
}

View File

@ -0,0 +1,222 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class InventoryTest
{
[TestMethod]
public async Task LoadItemDefinitionsAsync()
{
var result = await SteamInventory.WaitForDefinitions( 5 );
Assert.IsTrue( result );
result = await SteamInventory.WaitForDefinitions( 5 );
Assert.IsTrue( result );
}
[TestMethod]
public async Task GetDefinitions()
{
await SteamInventory.WaitForDefinitions();
Assert.IsNotNull( SteamInventory.Definitions );
foreach ( var def in SteamInventory.Definitions )
{
Console.WriteLine( $"[{def.Id:0000000000}] {def.Name} [{def.Type}]" );
}
}
[TestMethod]
public async Task GetDefinitionsWithPrices()
{
var defs = await SteamInventory.GetDefinitionsWithPricesAsync();
foreach ( var def in defs )
{
Console.WriteLine( $"[{def.Id:0000000000}] {def.Name} [{def.LocalPriceFormatted}]" );
}
}
[TestMethod]
public async Task GetAllItems()
{
await SteamInventory.WaitForDefinitions();
var result = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( result.HasValue );
Assert.IsTrue( result.Value.ItemCount > 0 );
using ( result )
{
var items = result.Value.GetItems( true );
Assert.IsNotNull( items );
foreach ( var item in items )
{
Console.WriteLine( $"{item.Id} / {item.DefId} / {item.Quantity} / {item.Def?.Name} /[{item.IsNoTrade}|{item.IsRemoved}|{item.IsConsumed}] " );
foreach ( var prop in item.Properties )
{
Console.WriteLine( $" {prop.Key} : {prop.Value}" );
}
}
}
}
[TestMethod]
public async Task GetItemSpecialProperties()
{
await SteamInventory.WaitForDefinitions();
var result = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( result.HasValue );
Assert.IsTrue( result.Value.ItemCount > 0 );
using ( result )
{
var items = result.Value.GetItems( true );
Assert.IsNotNull( items );
foreach ( var item in items )
{
Console.WriteLine( $"{item.Id} / {item.DefId} / {item.Quantity} / {item.Def?.Name} " );
Console.WriteLine( $" Acquired: {item.Acquired}" );
Console.WriteLine( $" Origin: {item.Origin}" );
}
}
}
[TestMethod]
public async Task GetAllItemsMultipleTimes()
{
await SteamInventory.WaitForDefinitions();
var fresult = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( fresult.HasValue );
Assert.IsTrue( fresult.Value.ItemCount > 0 );
await Task.Delay( 1000 );
var result = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( result.HasValue );
Assert.IsTrue( result.Value.GetItems().Length == fresult.Value.ItemCount );
await Task.Delay( 1000 );
result = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( result.HasValue );
Assert.IsTrue( result.Value.ItemCount == fresult.Value.ItemCount );
}
[TestMethod]
public async Task Items()
{
SteamInventory.GetAllItems();
await SteamInventory.WaitForDefinitions();
while ( SteamInventory.Items == null )
{
await Task.Delay( 10 );
}
Assert.IsNotNull( SteamInventory.Items );
foreach ( var item in SteamInventory.Items )
{
Console.WriteLine( $"{item.Id} / {item.DefId} / {item.Quantity} / {item.Def.Name}" );
}
}
[TestMethod]
public async Task GetExchanges()
{
var result = await SteamInventory.WaitForDefinitions( 5 );
Assert.IsTrue( result );
foreach ( var def in SteamInventory.Definitions )
{
var exchangelist = def.GetRecipes();
if ( exchangelist == null ) continue;
foreach ( var exchange in exchangelist )
{
Assert.AreEqual( exchange.Result, def );
Console.WriteLine( $"{def.Name}:" );
foreach ( var item in exchange.Ingredients )
{
Console.WriteLine( $" {item.Count} x {item.Definition.Name}" );
}
Console.WriteLine( $"" );
}
}
}
[TestMethod]
public async Task Serialize()
{
await SteamInventory.WaitForDefinitions();
var result = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( result.HasValue );
var data = result.Value.Serialize();
Assert.IsNotNull( data );
Console.WriteLine( string.Join( "", data.Select( x => x.ToString( "x" ) ) ) );
}
[TestMethod]
public async Task Deserialize()
{
await SteamInventory.WaitForDefinitions();
byte[] data = null;
int itemCount = 0;
// Serialize
{
var result = await SteamInventory.GetAllItemsAsync();
Assert.IsTrue( result.HasValue );
itemCount = result.Value.ItemCount;
data = result.Value.Serialize();
Assert.IsNotNull( data );
result.Value.Dispose();
}
await Task.Delay( 2000 );
// Deserialize
{
var result = await SteamInventory.DeserializeAsync( data );
Assert.IsTrue( result.HasValue );
Assert.AreEqual( itemCount, result.Value.ItemCount );
result.Value.Dispose();
}
}
}
}

View File

@ -0,0 +1,287 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class NetworkingSocketsTest
{
[TestMethod]
public async Task CreateRelayServer()
{
var si = SteamNetworkingSockets.CreateRelaySocket<TestSocketInterface>();
Console.WriteLine( $"Created Socket: {si}" );
// Give it a second for something to happen
await Task.Delay( 1000 );
si.Close();
}
[TestMethod]
public async Task CreateNormalServer()
{
var si = SteamNetworkingSockets.CreateNormalSocket<TestSocketInterface>( Data.NetAddress.AnyIp( 21893 ) );
Console.WriteLine( $"Created Socket: {si}" );
// Give it a second for something to happen
await Task.Delay( 1000 );
si.Close();
}
[TestMethod]
public async Task RelayEndtoEnd()
{
var socket = SteamNetworkingSockets.CreateRelaySocket<TestSocketInterface>( 7788 );
var server = socket.RunAsync();
await Task.Delay( 1000 );
var connection = SteamNetworkingSockets.ConnectRelay<TestConnectionInterface>( SteamClient.SteamId, 7788 );
var client = connection.RunAsync();
await Task.WhenAll( server, client );
}
[TestMethod]
public async Task NormalEndtoEnd()
{
var socket = SteamNetworkingSockets.CreateNormalSocket<TestSocketInterface>( NetAddress.AnyIp( 12445 ) );
var server = socket.RunAsync();
await Task.Delay( 1000 );
var connection = SteamNetworkingSockets.ConnectNormal<TestConnectionInterface>( NetAddress.From( System.Net.IPAddress.Parse( "127.0.0.1" ), 12445 ) );
var client = connection.RunAsync();
await Task.WhenAll( server, client );
}
private class TestConnectionInterface : ConnectionInterface
{
public override void OnConnectionChanged( ConnectionInfo data )
{
Console.WriteLine( $"[Connection][{Connection}] [{data.State}]" );
base.OnConnectionChanged( data );
}
public override void OnConnecting( ConnectionInfo data )
{
Console.WriteLine( $" - OnConnecting" );
base.OnConnecting( data );
}
/// <summary>
/// Client is connected. They move from connecting to Connections
/// </summary>
public override void OnConnected( ConnectionInfo data )
{
Console.WriteLine( $" - OnConnected" );
base.OnConnected( data );
}
/// <summary>
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
/// </summary>
public override void OnDisconnected( ConnectionInfo data )
{
Console.WriteLine( $" - OnDisconnected" );
base.OnDisconnected( data );
}
internal async Task RunAsync()
{
Console.WriteLine( "[Connection] RunAsync" );
var sw = System.Diagnostics.Stopwatch.StartNew();
while ( Connecting )
{
await Task.Delay( 10 );
if ( sw.Elapsed.TotalSeconds > 30 )
break;
}
if ( !Connected )
{
Console.WriteLine( "[Connection] Couldn't connect!" );
Console.WriteLine( Connection.DetailedStatus() );
return;
}
Console.WriteLine( "[Connection] Hey We're Connected!" );
sw = System.Diagnostics.Stopwatch.StartNew();
while ( Connected )
{
Receive();
await Task.Delay( 100 );
if ( sw.Elapsed.TotalSeconds > 10 )
{
Assert.Fail( "Client Took Too Long" );
break;
}
}
}
public override unsafe void OnMessage( IntPtr data, int size, long messageNum, long recvTime, int channel )
{
// We're only sending strings, so it's fine to read this like this
var str = UTF8Encoding.UTF8.GetString( (byte*) data, size );
Console.WriteLine( $"[Connection][{messageNum}][{recvTime}][{channel}] \"{str}\"" );
if ( str.Contains( "Hello" ) )
{
Connection.SendMessage( "Hello, How are you!?" );
Connection.SendMessage( "How do you like 20 messages in a row?" );
for ( int i=0; i<20; i++ )
{
Connection.SendMessage( $"BLAMMO!" );
}
}
if ( str.Contains( "status" ))
{
Console.WriteLine( Connection.DetailedStatus() );
}
if ( str.Contains( "how about yourself" ) )
{
Connection.SendMessage( "I'm great, but I have to go now, bye." );
}
if ( str.Contains( "hater" ) )
{
Close();
}
}
}
private class TestSocketInterface : SocketInterface
{
public bool HasFinished = false;
public override void OnConnectionChanged( Connection connection, ConnectionInfo data )
{
Console.WriteLine( $"[Socket{Socket}][{connection}] [{data.State}]" );
base.OnConnectionChanged( connection, data );
}
public override void OnConnecting( Connection connection, ConnectionInfo data )
{
Console.WriteLine( $" - OnConnecting" );
base.OnConnecting( connection, data );
}
/// <summary>
/// Client is connected. They move from connecting to Connections
/// </summary>
public override void OnConnected( Connection connection, ConnectionInfo data )
{
Console.WriteLine( $" - OnConnected" );
base.OnConnected( connection, data );
}
/// <summary>
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
/// </summary>
public override void OnDisconnected( Connection connection, ConnectionInfo data )
{
Console.WriteLine( $" - OnDisconnected" );
base.OnDisconnected( connection, data );
}
internal async Task RunAsync()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
while ( Connected.Count == 0 )
{
await Task.Delay( 10 );
if ( sw.Elapsed.TotalSeconds > 2 )
{
Assert.Fail( "Client Took Too Long To Connect" );
break;
}
}
await Task.Delay( 1000 );
var singleClient = Connected.First();
singleClient.SendMessage( "Hey?" );
await Task.Delay( 100 );
singleClient.SendMessage( "Anyone?" );
await Task.Delay( 100 );
singleClient.SendMessage( "What's this?" );
await Task.Delay( 100 );
singleClient.SendMessage( "What's your status?" );
await Task.Delay( 10 );
singleClient.SendMessage( "Greetings!!??" );
await Task.Delay( 100 );
singleClient.SendMessage( "Hello Client!?" );
sw = System.Diagnostics.Stopwatch.StartNew();
while ( Connected.Contains( singleClient ) )
{
Receive();
await Task.Delay( 100 );
if ( sw.Elapsed.TotalSeconds > 10 )
{
Assert.Fail( "Socket Took Too Long" );
break;
}
}
await Task.Delay( 1000 );
Close();
}
public override unsafe void OnMessage( Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel )
{
// We're only sending strings, so it's fine to read this like this
var str = UTF8Encoding.UTF8.GetString( (byte*)data, size );
Console.WriteLine( $"[SOCKET][{connection}[{identity}][{messageNum}][{recvTime}][{channel}] \"{str}\"" );
if ( str.Contains( "Hello, How are you" ) )
{
connection.SendMessage( "I'm great thanks, how about yourself?" );
}
if ( str.Contains( "bye" ) )
{
connection.SendMessage( "See you later, hater." );
connection.Flush();
connection.Close( true, 10, "Said Bye" );
}
}
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class NetworkUtilsTest
{
static string GarrysLocation = "lhr=19+1,ams=25+2/25+1,par=29+2,fra=31+3/30+1,lux=33+3,vie=44+4/41+1,waw=47+4/45+1,sto2=48+4/46+2,sto=50+5/46+2,iad=107+10/91+1,sgp=186+18,gru=252+25/234+1";
[TestMethod]
public async Task LocalPingLocation()
{
await SteamNetworkingUtils.WaitForPingDataAsync();
for ( int i = 0; i < 10; i++ )
{
var pl = SteamNetworkingUtils.LocalPingLocation;
if ( !pl.HasValue )
{
await Task.Delay( 1000 );
continue;
}
Console.WriteLine( $"{i} Seconds Until Result: {pl}" );
return;
}
Assert.Fail();
}
[TestMethod]
public void PingLocationParse()
{
var pl = Data.PingLocation.TryParseFromString( GarrysLocation );
Assert.IsTrue( pl.HasValue );
Console.WriteLine( $"Parsed OKAY! {pl}" );
}
[TestMethod]
public async Task GetEstimatedPing()
{
await SteamNetworkingUtils.WaitForPingDataAsync();
var garrysping = Data.PingLocation.TryParseFromString( GarrysLocation );
Assert.IsTrue( garrysping.HasValue );
var ping = SteamNetworkingUtils.EstimatePingTo( garrysping.Value );
Assert.IsTrue( ping > 0 );
Console.WriteLine( $"Ping returned: {ping}" );
}
}
}

View File

@ -0,0 +1,78 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class RemoteStorageTest
{
[TestMethod]
public void Quotas()
{
Console.WriteLine( $"SteamRemoteStorage.QuotaBytes: {SteamRemoteStorage.QuotaBytes}" );
Console.WriteLine( $"SteamRemoteStorage.QuotaRemainingBytes: {SteamRemoteStorage.QuotaRemainingBytes}" );
Console.WriteLine( $"SteamRemoteStorage.QuotaUsedBytes: {SteamRemoteStorage.QuotaUsedBytes}" );
}
[TestMethod]
public void IsCloudEnabled()
{
Console.WriteLine( $"SteamRemoteStorage.IsCloudEnabled: {SteamRemoteStorage.IsCloudEnabled}" );
Console.WriteLine( $"SteamRemoteStorage.IsCloudEnabledForAccount: {SteamRemoteStorage.IsCloudEnabledForAccount}" );
Console.WriteLine( $"SteamRemoteStorage.IsCloudEnabledForApp: {SteamRemoteStorage.IsCloudEnabledForApp}" );
}
[TestMethod]
public void FileWrite()
{
var rand = new Random();
var testFile = new byte[1024 * 1024 * 100];
for( int i=0; i< testFile.Length; i++ )
{
testFile[i] = (byte) i;
}
var written = SteamRemoteStorage.FileWrite( "testfile", testFile );
Assert.IsTrue( written );
Assert.IsTrue( SteamRemoteStorage.FileExists( "testfile" ) );
Assert.AreEqual( SteamRemoteStorage.FileSize( "testfile" ), testFile.Length );
}
[TestMethod]
public void FileRead()
{
FileWrite();
var data = SteamRemoteStorage.FileRead( "testfile" );
Assert.IsNotNull( data );
for ( int i = 0; i < data.Length; i++ )
{
Assert.AreEqual( data[i], (byte)i );
}
Assert.AreEqual( SteamRemoteStorage.FileSize( "testfile" ), data.Length );
Assert.AreEqual( SteamRemoteStorage.FileSize( "testfile" ), 1024 * 1024 * 100 );
}
[TestMethod]
public void Files()
{
foreach ( var file in SteamRemoteStorage.Files )
{
Console.WriteLine( $"{file} ({SteamRemoteStorage.FileSize(file)} {SteamRemoteStorage.FileTime( file )})" );
}
}
}
}

View File

@ -0,0 +1,229 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public partial class ServerListTest
{
[TestMethod]
public void IpAddressConversions()
{
var ipstr = "185.38.150.40";
var ip = IPAddress.Parse( ipstr );
var ip_int = Utility.IpToInt32( ip );
var ip_back = Utility.Int32ToIp( ip_int );
Console.WriteLine( "ipstr: " + ipstr );
Console.WriteLine( "ip: " + ip );
Console.WriteLine( "ip int: " + ip_int );
Console.WriteLine( "ip_back: " + ip_back );
}
[TestMethod]
public async Task ServerListInternetInterupted()
{
using ( var list = new ServerList.Internet() )
{
var task = list.RunQueryAsync();
await Task.Delay( 1000 );
Console.WriteLine( $"Querying.." );
list.Cancel();
foreach ( var s in list.Responsive )
{
Console.WriteLine( $"{s.Address} {s.Name}" );
}
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
Console.WriteLine( $"task.IsCompleted {task.IsCompleted}" );
}
}
[TestMethod]
public async Task ServerListInternet()
{
using ( var list = new ServerList.Internet() )
{
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
}
}
[TestMethod]
public async Task SourceQuery()
{
using ( var list = new ServerList.Internet() )
{
var task = list.RunQueryAsync();
await Task.Delay( 1000 );
list.Cancel();
foreach ( var s in list.Responsive.Take( 10 ).ToArray() )
{
Console.WriteLine( $"{s.Name} [{s.Address}]" );
var rules = await s.QueryRulesAsync();
Assert.IsNotNull( rules );
foreach ( var rule in rules )
{
Console.WriteLine( $" {rule.Key} = {rule.Value}" );
}
}
}
}
[TestMethod]
public async Task ServerListLan()
{
using ( var list = new ServerList.LocalNetwork() )
{
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
}
}
[TestMethod]
public async Task ServerListFavourites()
{
using ( var list = new ServerList.Favourites() )
{
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
}
}
[TestMethod]
public async Task ServerListFriends()
{
using ( var list = new ServerList.Friends() )
{
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
}
}
[TestMethod]
public async Task ServerListHistory()
{
using ( var list = new ServerList.History() )
{
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
}
}
[TestMethod]
public async Task FilterByMap()
{
using ( var list = new ServerList.Internet() )
{
list.AddFilter( "map", "de_dust" );
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
foreach ( var server in list.Responsive )
{
Assert.AreEqual( server.Map.ToLower(), "de_dust" );
Console.WriteLine( $"[{server.Map}] - {server.Name}" );
}
}
}
[TestMethod]
public async Task ServerListIps()
{
var ips = new string[]
{
"31.186.251.76",
"31.186.251.76",
"31.186.251.76",
"31.186.251.76",
"31.186.251.76",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"139.99.144.70",
"139.99.144.70",
"139.99.144.70",
"139.99.144.70",
"139.99.144.70",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"74.91.119.142",
"95.172.92.176",
"95.172.92.176",
"95.172.92.176",
"95.172.92.176",
"95.172.92.176",
"164.132.205.154",
"164.132.205.154",
"164.132.205.154",
"164.132.205.154",
"164.132.205.154",
};
using ( var list = new ServerList.IpList( ips ) )
{
var success = await list.RunQueryAsync();
Console.WriteLine( $"success {success}" );
Console.WriteLine( $"Found {list.Responsive.Count} Responsive Servers" );
Console.WriteLine( $"Found {list.Unresponsive.Count} Unresponsive Servers" );
Assert.AreNotEqual( list.Responsive.Count, 0 );
foreach ( var server in list.Responsive )
{
Console.WriteLine( $"[{server.Address}:{server.ConnectionPort}] - {server.Name}" );
}
}
}
}
}

View File

@ -0,0 +1,105 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class SteamMatchmakingTest
{
[TestMethod]
public async Task LobbyList()
{
await CreateLobby();
var list = await SteamMatchmaking.LobbyList
.RequestAsync();
if ( list == null )
{
Console.WriteLine( "No Lobbies Found!" );
return;
}
foreach ( var lobby in list )
{
Console.WriteLine( $"[{lobby.Id}] owned by {lobby.Owner} ({lobby.MemberCount}/{lobby.MaxMembers})" );
}
}
[TestMethod]
public async Task LobbyListWithAtLeastOne()
{
await CreateLobby();
await LobbyList();
}
[TestMethod]
public async Task CreateLobby()
{
var lobbyr = await SteamMatchmaking.CreateLobbyAsync( 32 );
if ( !lobbyr.HasValue )
{
Assert.Fail();
}
var lobby = lobbyr.Value;
lobby.SetPublic();
lobby.SetData( "gametype", "sausage" );
lobby.SetData( "dicks", "unlicked" );
Console.WriteLine( $"lobby: {lobby.Id}" );
foreach ( var entry in lobby.Data )
{
Console.WriteLine( $" - {entry.Key} {entry.Value}" );
}
Console.WriteLine( $"members: {lobby.MemberCount}/{lobby.MaxMembers}" );
Console.WriteLine( $"Owner: {lobby.Owner}" );
Console.WriteLine( $"Owner Is Local Player: {lobby.Owner.IsMe}" );
lobby.SendChatString( "Hello I Love Lobbies" );
}
[TestMethod]
public async Task LobbyChat()
{
SteamMatchmaking.OnChatMessage += ( lbby, member, message ) =>
{
Console.WriteLine( $"[{lbby}] {member}: {message}" );
};
var lobbyr = await SteamMatchmaking.CreateLobbyAsync( 10 );
if ( !lobbyr.HasValue )
Assert.Fail();
var lobby = lobbyr.Value;
lobby.SetPublic();
lobby.SetData( "name", "Dave's Chat Room" );
Console.WriteLine( $"lobby: {lobby.Id}" );
lobby.SendChatString( "Hello Friends, It's me - your big fat daddy" );
await Task.Delay( 50 );
lobby.SendChatString( "What? No love for daddy?" );
await Task.Delay( 500 );
lobby.SendChatString( "Okay I will LEAVE" );
lobby.SendChatString( "BYE FOREVER" );
await Task.Delay( 1000 );
lobby.Leave();
}
}
}

View File

@ -0,0 +1,37 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class SteamNetworkingTest
{
[TestMethod]
public async Task SendP2PPacket()
{
var sent = SteamNetworking.SendP2PPacket( SteamClient.SteamId, new byte[] { 1, 2, 3 } );
Assert.IsTrue( sent );
while ( !SteamNetworking.IsP2PPacketAvailable() )
{
await Task.Delay( 10 );
}
var packet = SteamNetworking.ReadP2PPacket();
Assert.IsTrue( packet.HasValue );
Assert.AreEqual( packet.Value.SteamId, SteamClient.SteamId );
Assert.AreEqual( packet.Value.Data[1], 2 );
Assert.AreEqual( packet.Value.Data.Length, 3 );
}
}
}

View File

@ -0,0 +1,182 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class UgcEditor
{
[TestMethod]
public async Task CreateFile()
{
var result = await Ugc.Editor.NewCommunityFile
.WithTitle( "Unit Test Created Item" )
.WithDescription( "This item was created by Facepunch Steamworks unit tests.\n\n" +
"It should have technically been deleted so you should never get to " +
"read this unless something terrible has happened." )
.WithTag( "Arsehole" )
.WithTag( "Spiteful" )
.WithTag( "Fat-Head" )
.SubmitAsync();
Assert.IsTrue( result.Success );
Assert.AreNotEqual( result.FileId.Value, 0 );
var deleted = await SteamUGC.DeleteFileAsync( result.FileId );
Assert.IsTrue( deleted );
}
[TestMethod]
public async Task CreateChineseFile()
{
string fileName = "这是我的项目";
string description = "此项目由Facepunch Steamworks单元测试创建";
var result = await Ugc.Editor.NewCommunityFile
.WithTitle( fileName )
.WithDescription( description )
.WithTag( "Arsehole" )
.WithTag( "Spiteful" )
.WithTag( "Fat-Head" )
.SubmitAsync();
Console.WriteLine( $"Title: {fileName}" );
Console.WriteLine( $"Description: {description}" );
Assert.IsTrue( result.Success );
Assert.AreNotEqual( result.FileId.Value, 0 );
var file = await Steamworks.SteamUGC.QueryFileAsync( result.FileId );
Console.WriteLine( $"FileId: {result.FileId}" );
Console.WriteLine( $"Title: {file.Value.Title}" );
Console.WriteLine( $"Description: {file.Value.Description}" );
Assert.AreEqual( file.Value.Title, fileName );
Assert.AreEqual( file.Value.Description, description );
var deleted = await SteamUGC.DeleteFileAsync( result.FileId );
Assert.IsTrue( deleted );
}
class ProgressBar : IProgress<float>
{
float Value = 0;
public void Report( float value )
{
if ( Value >= value ) return;
Value = value;
Console.WriteLine( value );
}
}
[TestMethod]
public async Task UploadBigishFile()
{
var created = Ugc.Editor.NewCommunityFile
.WithTitle( "Unit Test Upload Item" )
.WithDescription( "This item was created by Facepunch Steamworks unit tests.\n\n" +
"It should have technically been deleted so you should never get to " +
"read this unless something terrible has happened." )
//.WithTag( "Apple" )
//.WithTag( "Banana" )
;
// Make a folder
var testFolder = new System.IO.DirectoryInfo( "WorkshopUpload" );
if ( !testFolder.Exists ) testFolder.Create();
created = created.WithContent( testFolder.FullName );
// Upload a file of random bytes
var rand = new Random();
var testFile = new byte[1024 * 1024 * 32];
rand.NextBytes( testFile );
System.IO.File.WriteAllBytes( testFolder.FullName + "/testfile1.bin", testFile );
Console.WriteLine( testFolder.FullName );
try
{
var done = await created.SubmitAsync( new ProgressBar() );
Assert.IsTrue( done.Success );
Console.WriteLine( "item.Id: {0}", done.FileId );
var deleted = await SteamUGC.DeleteFileAsync( done.FileId );
Assert.IsTrue( deleted );
}
finally
{
System.IO.File.Delete( testFolder.FullName + "/testfile.bin" );
}
}
[TestMethod]
public async Task CreateAndThenEditFile()
{
PublishedFileId fileid = default;
//
// Make a file
//
{
var result = await Ugc.Editor.NewCommunityFile
.WithTitle( "Unedited File" )
.SubmitAsync();
Assert.IsTrue( result.Success );
Assert.AreNotEqual( result.FileId.Value, 0 );
fileid = result.FileId;
}
await Task.Delay( 1000 );
//
// Edit it
//
{
var editor = new Ugc.Editor( fileid );
editor = editor.WithTitle( "An Edited File" );
var result = await editor.SubmitAsync();
Assert.IsTrue( result.Success );
Assert.AreEqual( result.FileId, fileid );
}
await Task.Delay( 1000 );
//
// Make sure the edited file matches
//
{
var details = await SteamUGC.QueryFileAsync( fileid ) ?? throw new Exception( "Somethign went wrong" );
Assert.AreEqual( details.Id, fileid );
Assert.AreEqual( details.Title, "An Edited File" );
}
//
// Clean up
//
var deleted = await SteamUGC.DeleteFileAsync( fileid );
Assert.IsTrue( deleted );
}
}
}

View File

@ -0,0 +1,130 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class UgcQueryTests
{
[TestMethod]
public async Task QueryAll()
{
var q = Ugc.Query.All;
var result = await q.GetPageAsync( 1 );
Assert.IsNotNull( result );
Console.WriteLine( $"ResultCount: {result?.ResultCount}" );
Console.WriteLine( $"TotalCount: {result?.TotalCount}" );
}
[TestMethod]
public async Task QueryWithTags()
{
var q = Ugc.Query.All
.WithTag( "Version3" )
.WithTag( "Hunting Bow" )
.MatchAllTags();
var result = await q.GetPageAsync( 1 );
Assert.IsNotNull( result );
Assert.IsTrue( result?.ResultCount > 0 );
Console.WriteLine( $"ResultCount: {result?.ResultCount}" );
Console.WriteLine( $"TotalCount: {result?.TotalCount}" );
foreach ( var entry in result.Value.Entries )
{
Assert.IsTrue( entry.HasTag( "Version3" ), "Has Tag Version3" );
Assert.IsTrue( entry.HasTag( "Hunting Bow" ), "Has Tag HuntingBow" );
}
}
[TestMethod]
public async Task QueryAllFromFriends()
{
var q = Ugc.Query.All
.CreatedByFriends();
var result = await q.GetPageAsync( 1 );
Assert.IsNotNull( result );
Console.WriteLine( $"ResultCount: {result?.ResultCount}" );
Console.WriteLine( $"TotalCount: {result?.TotalCount}" );
foreach ( var entry in result.Value.Entries )
{
Console.WriteLine( $" {entry.Title}" );
}
}
[TestMethod]
public async Task QueryUserOwn()
{
var q = Ugc.Query.All
.WhereUserPublished();
var result = await q.GetPageAsync( 1 );
Assert.IsNotNull( result );
Console.WriteLine( $"ResultCount: {result?.ResultCount}" );
Console.WriteLine( $"TotalCount: {result?.TotalCount}" );
foreach ( var entry in result.Value.Entries )
{
Console.WriteLine( $" {entry.Title}" );
}
}
[TestMethod]
public async Task QueryGarry()
{
var q = Ugc.Query.All
.WhereUserPublished( 76561197960279927 );
var result = await q.GetPageAsync( 1 );
Assert.IsNotNull( result );
Assert.IsTrue( result?.ResultCount > 0 );
Console.WriteLine( $"ResultCount: {result?.ResultCount}" );
Console.WriteLine( $"TotalCount: {result?.TotalCount}" );
foreach ( var entry in result.Value.Entries )
{
Console.WriteLine( $" {entry.Title}" );
}
}
[TestMethod]
public async Task QuerySpecificFile()
{
var item = await SteamUGC.QueryFileAsync( 1734427277 );
Assert.IsTrue( item.HasValue );
Assert.IsNotNull( item.Value.Title );
Console.WriteLine( $"Title: {item?.Title}" );
Console.WriteLine( $"Desc: {item?.Description}" );
Console.WriteLine( $"Tags: {string.Join( ",", item?.Tags )}" );
Console.WriteLine( $"Author: {item?.Owner.Name} [{item?.Owner.Id}]" );
Console.WriteLine( $"PreviewImageUrl: {item?.PreviewImageUrl}" );
Console.WriteLine( $"NumComments: {item?.NumComments}" );
Console.WriteLine( $"Url: {item?.Url}" );
Console.WriteLine( $"Directory: {item?.Directory}" );
Console.WriteLine( $"IsInstalled: {item?.IsInstalled}" );
Console.WriteLine( $"IsAcceptedForUse: {item?.IsAcceptedForUse}" );
Console.WriteLine( $"IsPublic: {item?.IsPublic}" );
Console.WriteLine( $"Created: {item?.Created}" );
Console.WriteLine( $"Updated: {item?.Updated}" );
Console.WriteLine( $"Score: {item?.Score}" );
}
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class UgcTest
{
[TestMethod]
public void Download()
{
SteamUGC.Download( 1717844711 );
}
[TestMethod]
public async Task GetInformation()
{
var itemInfo = await Ugc.Item.GetAsync( 1720164672 );
Assert.IsTrue( itemInfo.HasValue );
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}" );
Console.WriteLine( $"Owner: {itemInfo?.Owner}" );
Console.WriteLine( $"Score: {itemInfo?.Score}" );
}
}
}

View File

@ -0,0 +1,197 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Steamworks.Data;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class UserStatsTest
{
[TestMethod]
public async Task AchievementList()
{
foreach ( var a in SteamUserStats.Achievements )
{
Console.WriteLine( $"{a.Identifier}" );
Console.WriteLine( $" a.State: {a.State}" );
Console.WriteLine( $" a.UnlockTime: {a.UnlockTime}" );
Console.WriteLine( $" a.Name: {a.Name}" );
Console.WriteLine( $" a.Description: {a.Description}" );
Console.WriteLine( $" a.GlobalUnlocked: {a.GlobalUnlocked}" );
var icon = await a.GetIconAsync();
Console.WriteLine( $" a.Icon: {icon}" );
}
}
[TestMethod]
public async Task PlayerCountAsync()
{
var players = await SteamUserStats.PlayerCountAsync();
Assert.AreNotEqual( players, -1 );
Console.WriteLine( $"players: {players}" );
}
public async Task StoreStats()
{
var result = Result.NotSettled;
SteamUserStats.OnUserStatsStored += ( r ) =>
{
result = r;
};
SteamUserStats.StoreStats();
while ( result == Result.NotSettled )
{
await Task.Delay( 10 );
}
Assert.AreEqual( result, Result.OK );
}
[TestMethod]
public async Task CreateLeaderboard()
{
var leaderboard = await SteamUserStats.FindOrCreateLeaderboardAsync( "Testleaderboard", Data.LeaderboardSort.Ascending, Data.LeaderboardDisplay.Numeric );
Assert.IsTrue( leaderboard.HasValue );
}
[TestMethod]
public async Task FindLeaderboard()
{
var leaderboard = await SteamUserStats.FindLeaderboardAsync( "Testleaderboard" );
Assert.IsTrue( leaderboard.HasValue );
}
[TestMethod]
public async Task SubmitScore()
{
var leaderboard = await SteamUserStats.FindLeaderboardAsync( "Testleaderboard" );
Assert.IsTrue( leaderboard.HasValue );
var result = await leaderboard.Value.SubmitScoreAsync( 576 );
Assert.IsTrue( result.HasValue );
Console.WriteLine( $"result.Changed: {result?.Changed}" );
Console.WriteLine( $"result.OldGlobalRank: {result?.OldGlobalRank}" );
Console.WriteLine( $"result.NewGlobalRank: {result?.NewGlobalRank}" );
Console.WriteLine( $"result.RankChange: {result?.RankChange}" );
Console.WriteLine( $"result.Score: {result?.Score}" );
}
[TestMethod]
public async Task ReplaceScore()
{
var leaderboard = await SteamUserStats.FindLeaderboardAsync( "Testleaderboard" );
Assert.IsTrue( leaderboard.HasValue );
var result = await leaderboard.Value.ReplaceScore( 576 );
Assert.IsTrue( result.HasValue );
Console.WriteLine( $"result.Changed: {result?.Changed}" );
Console.WriteLine( $"result.OldGlobalRank: {result?.OldGlobalRank}" );
Console.WriteLine( $"result.NewGlobalRank: {result?.NewGlobalRank}" );
Console.WriteLine( $"result.RankChange: {result?.RankChange}" );
Console.WriteLine( $"result.Score: {result?.Score}" );
}
[TestMethod]
public async Task GetScoresFromFriends()
{
var leaderboard = await SteamUserStats.FindLeaderboardAsync( "Testleaderboard" );
var friendScores = await leaderboard.Value.GetScoresFromFriendsAsync();
foreach ( var e in friendScores )
{
Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" );
}
}
[TestMethod]
public async Task GetScoresAroundUserAsync()
{
var leaderboard = await SteamUserStats.FindLeaderboardAsync( "Testleaderboard" );
Assert.IsTrue( leaderboard.HasValue );
for ( int i = 1; i < 10; i++ )
{
// Get entries around user
var relativeScores = await leaderboard.Value.GetScoresAroundUserAsync( -i, i );
Assert.IsNotNull( relativeScores );
Console.WriteLine( $"" );
Console.WriteLine( $"Relative Scores:" );
foreach ( var e in relativeScores )
{
Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" );
}
}
}
[TestMethod]
public async Task GetScoresAsync()
{
var leaderboard = await SteamUserStats.FindLeaderboardAsync( "Testleaderboard" );
Assert.IsTrue( leaderboard.HasValue );
// Get top 20 global scores
var globalsScores = await leaderboard.Value.GetScoresAsync( 20 );
Assert.IsNotNull( globalsScores );
Console.WriteLine( $"" );
Console.WriteLine( $"Global Scores:" );
foreach ( var e in globalsScores )
{
Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" );
}
}
[TestMethod]
public void GetStatInt()
{
var deaths = new Stat( "deaths" );
Console.WriteLine( $"{deaths.Name} {deaths.GetInt()} times" );
Console.WriteLine( $"{deaths.Name} {deaths.GetFloat()} times" );
Assert.AreNotEqual( 0, deaths.GetInt() );
}
[TestMethod]
public async Task GetStatGlobalInt()
{
var deaths = new Stat( "deaths" );
await deaths.GetGlobalIntDaysAsync( 5 );
var totalStartups = deaths.GetGlobalInt();
Assert.AreNotEqual( 0, totalStartups );
Console.WriteLine( $"Rust has had {totalStartups} deaths" );
}
[TestMethod]
public async Task GetStatGlobalHistoryInt()
{
var deaths = new Stat( "deaths" );
var history = await deaths.GetGlobalIntDaysAsync( 10 );
Assert.AreNotEqual( 0, history.Length );
for ( int i=0; i< history.Length; i++ )
{
Console.WriteLine( $"{i} : {history[i]}" );
}
}
}
}

View File

@ -0,0 +1,155 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class UserTest
{
[TestMethod]
public void GetVoice()
{
using ( var stream = new MemoryStream() )
{
int compressed = 0;
SteamUser.VoiceRecord = true;
var sw = Stopwatch.StartNew();
while ( sw.Elapsed.TotalSeconds < 3 )
{
System.Threading.Thread.Sleep( 10 );
compressed += SteamUser.ReadVoiceData( stream );
}
Assert.AreEqual( compressed, stream.Length );
Console.WriteLine( $"compressed: {compressed}", compressed );
Console.WriteLine( $"stream.Length: {stream.Length}", stream.Length );
}
}
[TestMethod]
public void OptimalSampleRate()
{
var rate = SteamUser.OptimalSampleRate;
Assert.AreNotEqual( rate, 0 );
Console.WriteLine( $"User.OptimalSampleRate: {SteamUser.OptimalSampleRate}" );
}
[TestMethod]
public void IsLoggedOn()
{
Assert.AreNotEqual( false, SteamClient.IsLoggedOn );
Console.WriteLine( $"User.IsLoggedOn: {SteamClient.IsLoggedOn}" );
}
[TestMethod]
public void SteamID()
{
Assert.AreNotEqual( 0, SteamClient.SteamId.Value );
Console.WriteLine( $"User.SteamID: {SteamClient.SteamId.Value}" );
}
[TestMethod]
public void AuthSession()
{
var ticket = SteamUser.GetAuthSessionTicket();
Assert.AreNotEqual( 0, ticket.Handle );
Assert.AreNotEqual( 0, ticket.Data.Length );
Console.WriteLine( $"ticket.Handle: {ticket.Handle}" );
Console.WriteLine( $"ticket.Data: { string.Join( "", ticket.Data.Select( x => x.ToString( "x" ) ) ) }" );
var result = SteamUser.BeginAuthSession( ticket.Data, SteamClient.SteamId );
Console.WriteLine( $"result: { result }" );
Assert.AreEqual( result, BeginAuthResult.OK );
SteamUser.EndAuthSession( SteamClient.SteamId );
}
[TestMethod]
public async Task AuthSessionAsync()
{
var ticket = await SteamUser.GetAuthSessionTicketAsync( 5.0 );
Assert.AreNotEqual( 0, ticket.Handle );
Assert.AreNotEqual( 0, ticket.Data.Length );
Console.WriteLine( $"ticket.Handle: {ticket.Handle}" );
Console.WriteLine( $"ticket.Data: { string.Join( "", ticket.Data.Select( x => x.ToString( "x" ) ) ) }" );
}
[TestMethod]
public void SteamLevel()
{
Assert.AreNotEqual( 0, SteamUser.SteamLevel );
Console.WriteLine( $"User.SteamLevel: {SteamUser.SteamLevel}" );
}
[TestMethod]
public void Name()
{
Console.WriteLine( $"SteamClient.Name: {SteamClient.Name}" );
}
[TestMethod]
public async Task GetStoreAuthUrlAsync()
{
var rustskins = await SteamUser.GetStoreAuthUrlAsync( "https://store.steampowered.com/itemstore/252490/" );
Assert.IsNotNull( rustskins );
Console.WriteLine( $"rustskins: {rustskins}" );
}
[TestMethod]
public void IsPhoneVerified()
{
Console.WriteLine( $"User.IsPhoneVerified: {SteamUser.IsPhoneVerified}" );
}
[TestMethod]
public void IsTwoFactorEnabled()
{
Console.WriteLine( $"User.IsTwoFactorEnabled: {SteamUser.IsTwoFactorEnabled}" );
}
[TestMethod]
public void IsPhoneIdentifying()
{
Console.WriteLine( $"User.IsPhoneIdentifying: {SteamUser.IsPhoneIdentifying}" );
}
[TestMethod]
public void IsPhoneRequiringVerification()
{
Console.WriteLine( $"User.IsPhoneRequiringVerification: {SteamUser.IsPhoneRequiringVerification}" );
}
[TestMethod]
public async Task RequestEncryptedAppTicketAsyncWithData()
{
var data = await SteamUser.RequestEncryptedAppTicketAsync( new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 } );
Assert.IsNotNull( data );
Console.WriteLine( $"data: {string.Join( "", data.Select( x => x.ToString( "x" ) ))}" );
}
[TestMethod]
public async Task RequestEncryptedAppTicketAsync()
{
var data = await SteamUser.RequestEncryptedAppTicketAsync();
Assert.IsNotNull( data );
Console.WriteLine( $"data: {string.Join( "", data.Select( x => x.ToString( "x" ) ) )}" );
}
}
}

View File

@ -0,0 +1,117 @@
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Steamworks
{
[TestClass]
[DeploymentItem( "steam_api64.dll" )]
public class UtilsTest
{
[TestMethod]
public void SecondsSinceAppActive()
{
var time = SteamUtils.SecondsSinceAppActive;
Console.WriteLine( $"{time}" );
}
[TestMethod]
public void SecondsSinceComputerActive()
{
var time = SteamUtils.SecondsSinceComputerActive;
Console.WriteLine( $"{time}" );
}
[TestMethod]
public void ConnectedUniverse()
{
var u = SteamUtils.ConnectedUniverse;
Console.WriteLine( $"{u}" );
}
[TestMethod]
public void SteamServerTime()
{
var time = SteamUtils.SteamServerTime;
Console.WriteLine( $"{time}" );
}
[TestMethod]
public void IpCountry()
{
var cnt = SteamUtils.IpCountry;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public void UsingBatteryPower()
{
var cnt = SteamUtils.UsingBatteryPower;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public void CurrentBatteryPower()
{
var cnt = SteamUtils.CurrentBatteryPower;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public void AppId()
{
var cnt = SteamClient.AppId;
Assert.IsTrue( cnt.Value > 0 );
Console.WriteLine( $"{cnt.Value}" );
}
[TestMethod]
public void IsOverlayEnabled()
{
var cnt = SteamUtils.IsOverlayEnabled;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public async Task CheckFileSignature()
{
var sig = await SteamUtils.CheckFileSignatureAsync( "hl2.exe" );
Console.WriteLine( $"{sig}" );
}
[TestMethod]
public void SteamUILanguage()
{
var cnt = SteamUtils.SteamUILanguage;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public void IsSteamRunningInVR()
{
var cnt = SteamUtils.IsSteamRunningInVR;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public void IsSteamInBigPictureMode()
{
var cnt = SteamUtils.IsSteamInBigPictureMode;
Console.WriteLine( $"{cnt}" );
}
[TestMethod]
public void VrHeadsetStreaming()
{
var cnt = SteamUtils.VrHeadsetStreaming;
Console.WriteLine( $"{cnt}" );
}
}
}

View File

@ -0,0 +1,74 @@
"In Game Actions"
{
"actions"
{
"InGameControls"
{
"title" "#Set_Ingame"
"StickPadGyro"
{
"Move"
{
"title" "#Action_Move"
"input_mode" "joystick_move"
}
"Camera"
{
"title" "#Action_Camera"
"input_mode" "absolute_mouse"
}
}
"AnalogTrigger"
{
"Throttle" "#Action_Throttle"
}
"Button"
{
"fire" "#Action_Fire"
"Jump" "#Action_Jump"
"pause_menu" "#Action_Menu"
}
}
"MenuControls"
{
"title" "#Set_Menu"
"StickPadGyro"
{
}
"AnalogTrigger"
{
}
"Button"
{
"menu_up" "#Menu_Up"
"menu_down" "#Menu_Down"
"menu_left" "#Menu_Left"
"menu_right" "#Menu_Right"
"menu_select" "#Menu_Select"
"menu_cancel" "#Menu_Cancel"
"pause_menu" "#Action_ReturnToGame"
}
}
}
"localization"
{
"english"
{
"Set_Ingame" "In-Game Controls"
"Set_Menu" "Menu Controls"
"Action_Move" "Movement"
"Action_Camera" "Camera"
"Action_Throttle" "Throttle"
"Action_Fire" "Fire Weapon"
"Action_Jump" "Jump"
"Action_Menu" "Pause Menu"
"Action_ReturnToGame" "Return To Game"
"Menu_Up" "Up"
"Menu_Down" "Down"
"Menu_Left" "Left"
"Menu_Right" "Right"
"Menu_Select" "Select"
"Menu_Cancel" "Cancel"
}
}
}

View File

@ -0,0 +1,74 @@
"In Game Actions"
{
"actions"
{
"InGameControls"
{
"title" "#Set_Ingame"
"StickPadGyro"
{
"Move"
{
"title" "#Action_Move"
"input_mode" "joystick_move"
}
"Camera"
{
"title" "#Action_Camera"
"input_mode" "absolute_mouse"
}
}
"AnalogTrigger"
{
"Throttle" "#Action_Throttle"
}
"Button"
{
"fire" "#Action_Fire"
"Jump" "#Action_Jump"
"pause_menu" "#Action_Menu"
}
}
"MenuControls"
{
"title" "#Set_Menu"
"StickPadGyro"
{
}
"AnalogTrigger"
{
}
"Button"
{
"menu_up" "#Menu_Up"
"menu_down" "#Menu_Down"
"menu_left" "#Menu_Left"
"menu_right" "#Menu_Right"
"menu_select" "#Menu_Select"
"menu_cancel" "#Menu_Cancel"
"pause_menu" "#Action_ReturnToGame"
}
}
}
"localization"
{
"english"
{
"Set_Ingame" "In-Game Controls"
"Set_Menu" "Menu Controls"
"Action_Move" "Movement"
"Action_Camera" "Camera"
"Action_Throttle" "Throttle"
"Action_Fire" "Fire Weapon"
"Action_Jump" "Jump"
"Action_Menu" "Pause Menu"
"Action_ReturnToGame" "Return To Game"
"Menu_Up" "Up"
"Menu_Down" "Down"
"Menu_Left" "Left"
"Menu_Right" "Right"
"Menu_Select" "Select"
"Menu_Cancel" "Cancel"
}
}
}

View File

@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="MSTest.TestAdapter" version="2.0.0-beta4" targetFramework="net46" />
<package id="MSTest.TestFramework" version="2.0.0-beta4" targetFramework="net46" />
<package id="Newtonsoft.Json" version="9.0.2-beta1" targetFramework="net452" />
</packages>

View File

@ -1,32 +1,116 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26730.12
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks", "Facepunch.Steamworks\Facepunch.Steamworks.csproj", "{91962664-EB42-472A-94C8-C4FFEB44CC4B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facepunch.Steamworks.Test", "Facepunch.Steamworks.Test\Facepunch.Steamworks.Test.csproj", "{3F6183AD-D966-44F2-A6EB-42E61E591B49}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Generator", "Generator\Generator.csproj", "{B7225D11-2AAA-49D6-AE93-A73696EA35FE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks.Win64", "Facepunch.Steamworks\Facepunch.Steamworks.Win64.csproj", "{8C73DA93-73AD-4445-9A2C-15D4A44337D3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks.Posix64", "Facepunch.Steamworks\Facepunch.Steamworks.Posix64.csproj", "{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks.Win32", "Facepunch.Steamworks\Facepunch.Steamworks.Win32.csproj", "{2D6247F6-8AB2-405F-A00E-3A364B808A55}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Facepunch.Steamworks.Posix32", "Facepunch.Steamworks\Facepunch.Steamworks.Posix32.csproj", "{C62FF421-BE44-4DB0-B99A-E13E007A30B9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facepunch.Steamworks.TestWin32", "Facepunch.Steamworks.Test\Facepunch.Steamworks.TestWin32.csproj", "{3F6183AD-D966-44F2-A6EB-42E61E591B49}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Facepunch.Steamworks.TestWin64", "Facepunch.Steamworks.Test\Facepunch.Steamworks.TestWin64.csproj", "{165081E3-BD96-404B-B83E-A635F1AF7CDE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91962664-EB42-472A-94C8-C4FFEB44CC4B}.Release|Any CPU.Build.0 = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|Any CPU.Build.0 = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|x64.ActiveCfg = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|x64.Build.0 = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|x86.ActiveCfg = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Debug|x86.Build.0 = Debug|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|Any CPU.Build.0 = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|x64.ActiveCfg = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|x64.Build.0 = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|x86.ActiveCfg = Release|Any CPU
{B7225D11-2AAA-49D6-AE93-A73696EA35FE}.Release|x86.Build.0 = Release|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Debug|x64.ActiveCfg = Debug|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Debug|x64.Build.0 = Debug|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Debug|x86.ActiveCfg = Debug|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Debug|x86.Build.0 = Debug|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Release|Any CPU.Build.0 = Release|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Release|x64.ActiveCfg = Release|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Release|x64.Build.0 = Release|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Release|x86.ActiveCfg = Release|Any CPU
{8C73DA93-73AD-4445-9A2C-15D4A44337D3}.Release|x86.Build.0 = Release|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Debug|x64.ActiveCfg = Debug|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Debug|x64.Build.0 = Debug|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Debug|x86.ActiveCfg = Debug|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Debug|x86.Build.0 = Debug|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Release|Any CPU.Build.0 = Release|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Release|x64.ActiveCfg = Release|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Release|x64.Build.0 = Release|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Release|x86.ActiveCfg = Release|Any CPU
{12478BAE-7C1F-4FFD-B903-E1DDA6426DDF}.Release|x86.Build.0 = Release|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Debug|x64.ActiveCfg = Debug|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Debug|x64.Build.0 = Debug|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Debug|x86.ActiveCfg = Debug|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Debug|x86.Build.0 = Debug|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Release|Any CPU.Build.0 = Release|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Release|x64.ActiveCfg = Release|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Release|x64.Build.0 = Release|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Release|x86.ActiveCfg = Release|Any CPU
{2D6247F6-8AB2-405F-A00E-3A364B808A55}.Release|x86.Build.0 = Release|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Debug|x64.ActiveCfg = Debug|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Debug|x64.Build.0 = Debug|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Debug|x86.ActiveCfg = Debug|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Debug|x86.Build.0 = Debug|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Release|Any CPU.Build.0 = Release|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Release|x64.ActiveCfg = Release|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Release|x64.Build.0 = Release|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Release|x86.ActiveCfg = Release|Any CPU
{C62FF421-BE44-4DB0-B99A-E13E007A30B9}.Release|x86.Build.0 = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|x64.ActiveCfg = Debug|x64
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|x64.Build.0 = Debug|x64
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|x86.ActiveCfg = Debug|x86
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Debug|x86.Build.0 = Debug|x86
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|Any CPU.Build.0 = Release|Any CPU
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|x64.ActiveCfg = Release|x64
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|x64.Build.0 = Release|x64
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|x86.ActiveCfg = Release|x86
{3F6183AD-D966-44F2-A6EB-42E61E591B49}.Release|x86.Build.0 = Release|x86
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Debug|x64.ActiveCfg = Debug|x64
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Debug|x64.Build.0 = Debug|x64
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Debug|x86.ActiveCfg = Debug|x86
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Debug|x86.Build.0 = Debug|x86
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Release|Any CPU.Build.0 = Release|Any CPU
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Release|x64.ActiveCfg = Release|x64
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Release|x64.Build.0 = Release|x64
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Release|x86.ActiveCfg = Release|x86
{165081E3-BD96-404B-B83E-A635F1AF7CDE}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,219 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facepunch.Steamworks.Interop;
namespace Facepunch.Steamworks
{
/// <summary>
/// Implements shared functionality between Steamworks.Client and Steamworks.Server
/// </summary>
public class BaseSteamworks : IDisposable
{
/// <summary>
/// Current running program's AppId
/// </summary>
public uint AppId { get; internal set; }
public Networking Networking { get; internal set; }
public Inventory Inventory { get; internal set; }
public Workshop Workshop { get; internal set; }
internal event Action OnUpdate;
internal Interop.NativeInterface native;
private List<SteamNative.CallbackHandle> CallbackHandles = new List<SteamNative.CallbackHandle>();
private List<SteamNative.CallResult> CallResults = new List<SteamNative.CallResult>();
protected bool disposed = false;
protected BaseSteamworks( uint appId )
{
AppId = appId;
//
// No need for the "steam_appid.txt" file any more
//
System.Environment.SetEnvironmentVariable("SteamAppId", AppId.ToString());
System.Environment.SetEnvironmentVariable("SteamGameId", AppId.ToString());
}
~BaseSteamworks()
{
Dispose();
}
public virtual void Dispose()
{
if ( disposed ) return;
Callbacks.Clear();
foreach ( var h in CallbackHandles )
{
h.Dispose();
}
CallbackHandles.Clear();
foreach ( var h in CallResults )
{
h.Dispose();
}
CallResults.Clear();
if ( Workshop != null )
{
Workshop.Dispose();
Workshop = null;
}
if ( Inventory != null )
{
Inventory.Dispose();
Inventory = null;
}
if ( Networking != null )
{
Networking.Dispose();
Networking = null;
}
if ( native != null )
{
native.Dispose();
native = null;
}
System.Environment.SetEnvironmentVariable("SteamAppId", null );
System.Environment.SetEnvironmentVariable("SteamGameId", null );
disposed = true;
}
protected void SetupCommonInterfaces()
{
Networking = new Steamworks.Networking( this, native.networking );
Inventory = new Steamworks.Inventory( this, native.inventory, IsGameServer );
Workshop = new Steamworks.Workshop( this, native.ugc, native.remoteStorage );
}
/// <summary>
/// Returns true if this instance has initialized properly.
/// If this returns false you should Dispose and throw an error.
/// </summary>
public bool IsValid
{
get { return native != null; }
}
internal virtual bool IsGameServer { get { return false; } }
internal void RegisterCallbackHandle( SteamNative.CallbackHandle handle )
{
CallbackHandles.Add( handle );
}
internal void RegisterCallResult( SteamNative.CallResult handle )
{
CallResults.Add( handle );
}
internal void UnregisterCallResult( SteamNative.CallResult handle )
{
CallResults.Remove( handle );
}
public virtual void Update()
{
Networking.Update();
RunUpdateCallbacks();
}
/// <summary>
/// This gets called automatically in Update. Only call it manually if you know why you're doing it.
/// </summary>
public void RunUpdateCallbacks()
{
if ( OnUpdate != null )
OnUpdate();
for( int i=0; i < CallResults.Count; i++ )
{
CallResults[i].Try();
}
//
// The SourceServerQuery's happen in another thread, so we
// query them to see if they're finished, and if so post a callback
// in our main thread. This will all suck less once we have async.
//
Facepunch.Steamworks.SourceServerQuery.Cycle();
}
/// <summary>
/// Run Update until func returns false.
/// This will cause your program to lock up until it finishes.
/// This is useful for things like tests or command line utilities etc.
/// </summary>
public void UpdateWhile( Func<bool> func )
{
const int sleepMs = 1;
while ( func() )
{
Update();
#if NET_CORE
System.Threading.Tasks.Task.Delay( sleepMs ).Wait();
#else
System.Threading.Thread.Sleep( sleepMs );
#endif
}
}
/// <summary>
/// Debug function, called for every callback. Only really used to confirm that callbacks are working properly.
/// </summary>
public Action<object> OnAnyCallback;
Dictionary<Type, List<Action<object>>> Callbacks = new Dictionary<Type, List<Action<object>>>();
internal List<Action<object>> CallbackList( Type T )
{
List<Action<object>> list = null;
if ( !Callbacks.TryGetValue( T, out list ) )
{
list = new List<Action<object>>();
Callbacks[T] = list;
}
return list;
}
internal void OnCallback<T>( T data )
{
var list = CallbackList( typeof( T ) );
foreach ( var i in list )
{
i( data );
}
if ( OnAnyCallback != null )
{
OnAnyCallback.Invoke( data );
}
}
internal void RegisterCallback<T>( Action<T> func )
{
var list = CallbackList( typeof( T ) );
list.Add( ( o ) => func( (T) o ) );
}
}
}

View File

@ -0,0 +1,43 @@
using System;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using Steamworks.Data;
namespace Steamworks
{
[StructLayout( LayoutKind.Sequential )]
internal partial class Callback
{
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void Run( IntPtr thisptr, IntPtr pvParam );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate void RunCall( IntPtr thisptr, IntPtr pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall );
[UnmanagedFunctionPointer( CallingConvention.ThisCall )]
public delegate int GetCallbackSizeBytes( IntPtr thisptr );
internal enum Flags : byte
{
Registered = 0x01,
GameServer = 0x02
}
public IntPtr vTablePtr;
public byte CallbackFlags;
public int CallbackId;
//
// These are functions that are on CCallback but are never called
// We could just send a IntPtr.Zero but it's probably safer to throw a
// big apeshit message if steam changes its behaviour at some point
//
[MonoPInvokeCallback]
internal static void RunStub( IntPtr self, IntPtr param, bool failure, SteamAPICall_t call ) =>
throw new System.Exception( "Something changed in the Steam API and now CCallbackBack is calling the CallResult function [Run( void *pvParam, bool bIOFailure, SteamAPICall_t hSteamAPICall )]" );
[MonoPInvokeCallback]
internal static int SizeStub( IntPtr self ) =>
throw new System.Exception( "Something changed in the Steam API and now CCallbackBack is calling the GetSize function [GetCallbackSizeBytes()]" );
};
}

View File

@ -0,0 +1,135 @@
using Steamworks.Data;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Steamworks
{
//
// Created on registration of a callback
//
internal class Event : IDisposable
{
internal static List<IDisposable> AllClient = new List<IDisposable>();
internal static List<IDisposable> AllServer = new List<IDisposable>();
internal static void DisposeAllClient()
{
foreach ( var a in AllClient.ToArray() )
{
a.Dispose();
}
AllClient.Clear();
}
internal static void DisposeAllServer()
{
foreach ( var a in AllServer.ToArray() )
{
a.Dispose();
}
AllServer.Clear();
}
internal static void Register( Callback.Run func, int size, int callbackId, bool gameserver )
{
var r = new Event();
r.vTablePtr = BuildVTable( func, r.Allocations );
//
// Create the callback object
//
var cb = new Callback();
cb.vTablePtr = r.vTablePtr;
cb.CallbackFlags = gameserver ? (byte)0x02 : (byte)0;
cb.CallbackId = callbackId;
//
// Pin the callback, so it doesn't get garbage collected and we can pass the pointer to native
//
r.PinnedCallback = GCHandle.Alloc( cb, GCHandleType.Pinned );
//
// Register the callback with Steam
//
SteamClient.RegisterCallback( r.PinnedCallback.AddrOfPinnedObject(), cb.CallbackId );
r.IsAllocated = true;
if ( gameserver )
Event.AllServer.Add( r );
else
Event.AllClient.Add( r );
}
static IntPtr BuildVTable( Callback.Run run, List<GCHandle> allocations )
{
var RunStub = (Callback.RunCall)Callback.RunStub;
var SizeStub = (Callback.GetCallbackSizeBytes)Callback.SizeStub;
allocations.Add( GCHandle.Alloc( run ) );
allocations.Add( GCHandle.Alloc( RunStub ) );
allocations.Add( GCHandle.Alloc( SizeStub ) );
var a = Marshal.GetFunctionPointerForDelegate<Callback.Run>( run );
var b = Marshal.GetFunctionPointerForDelegate<Callback.RunCall>( RunStub );
var c = Marshal.GetFunctionPointerForDelegate<Callback.GetCallbackSizeBytes>( SizeStub );
var vt = Marshal.AllocHGlobal( IntPtr.Size * 3 );
// Windows switches the function positions
#if PLATFORM_WIN
Marshal.WriteIntPtr( vt, IntPtr.Size * 0, b );
Marshal.WriteIntPtr( vt, IntPtr.Size * 1, a );
Marshal.WriteIntPtr( vt, IntPtr.Size * 2, c );
#else
Marshal.WriteIntPtr( vt, IntPtr.Size * 0, a );
Marshal.WriteIntPtr( vt, IntPtr.Size * 1, b );
Marshal.WriteIntPtr( vt, IntPtr.Size * 2, c );
#endif
return vt;
}
bool IsAllocated;
List<GCHandle> Allocations = new List<GCHandle>();
internal IntPtr vTablePtr;
internal GCHandle PinnedCallback;
public void Dispose()
{
if ( !IsAllocated ) return;
IsAllocated = false;
if ( !PinnedCallback.IsAllocated )
throw new System.Exception( "Callback isn't allocated!?" );
SteamClient.UnregisterCallback( PinnedCallback.AddrOfPinnedObject() );
foreach ( var a in Allocations )
{
if ( a.IsAllocated )
a.Free();
}
Allocations = null;
PinnedCallback.Free();
if ( vTablePtr != IntPtr.Zero )
{
Marshal.FreeHGlobal( vTablePtr );
vTablePtr = IntPtr.Zero;
}
}
~Event()
{
Dispose();
}
}
}

View File

@ -1,118 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks.Callbacks
{
public delegate void FailureCallback( Result reason );
public enum Result : int
{
OK = 1, // success
Fail = 2, // generic failure
NoConnection = 3, // no/failed network connection
// k_EResultNoConnectionRetry = 4, // OBSOLETE - removed
InvalidPassword = 5, // password/ticket is invalid
LoggedInElsewhere = 6, // same user logged in elsewhere
InvalidProtocolVer = 7, // protocol version is incorrect
InvalidParam = 8, // a parameter is incorrect
FileNotFound = 9, // file was not found
Busy = 10, // called method busy - action not taken
InvalidState = 11, // called object was in an invalid state
InvalidName = 12, // name is invalid
InvalidEmail = 13, // email is invalid
DuplicateName = 14, // name is not unique
AccessDenied = 15, // access is denied
Timeout = 16, // operation timed out
Banned = 17, // VAC2 banned
AccountNotFound = 18, // account not found
InvalidSteamID = 19, // steamID is invalid
ServiceUnavailable = 20, // The requested service is currently unavailable
NotLoggedOn = 21, // The user is not logged on
Pending = 22, // Request is pending (may be in process, or waiting on third party)
EncryptionFailure = 23, // Encryption or Decryption failed
InsufficientPrivilege = 24, // Insufficient privilege
LimitExceeded = 25, // Too much of a good thing
Revoked = 26, // Access has been revoked (used for revoked guest passes)
Expired = 27, // License/Guest pass the user is trying to access is expired
AlreadyRedeemed = 28, // Guest pass has already been redeemed by account, cannot be acked again
DuplicateRequest = 29, // The request is a duplicate and the action has already occurred in the past, ignored this time
AlreadyOwned = 30, // All the games in this guest pass redemption request are already owned by the user
IPNotFound = 31, // IP address not found
PersistFailed = 32, // failed to write change to the data store
LockingFailed = 33, // failed to acquire access lock for this operation
LogonSessionReplaced = 34,
ConnectFailed = 35,
HandshakeFailed = 36,
IOFailure = 37,
RemoteDisconnect = 38,
ShoppingCartNotFound = 39, // failed to find the shopping cart requested
Blocked = 40, // a user didn't allow it
Ignored = 41, // target is ignoring sender
NoMatch = 42, // nothing matching the request found
AccountDisabled = 43,
ServiceReadOnly = 44, // this service is not accepting content changes right now
AccountNotFeatured = 45, // account doesn't have value, so this feature isn't available
AdministratorOK = 46, // allowed to take this action, but only because requester is admin
ContentVersion = 47, // A Version mismatch in content transmitted within the Steam protocol.
TryAnotherCM = 48, // The current CM can't service the user making a request, user should try another.
PasswordRequiredToKickSession = 49,// You are already logged in elsewhere, this cached credential login has failed.
AlreadyLoggedInElsewhere = 50, // You are already logged in elsewhere, you must wait
Suspended = 51, // Long running operation (content download) suspended/paused
Cancelled = 52, // Operation canceled (typically by user: content download)
DataCorruption = 53, // Operation canceled because data is ill formed or unrecoverable
DiskFull = 54, // Operation canceled - not enough disk space.
RemoteCallFailed = 55, // an remote call or IPC call failed
PasswordUnset = 56, // Password could not be verified as it's unset server side
ExternalAccountUnlinked = 57, // External account (PSN, Facebook...) is not linked to a Steam account
PSNTicketInvalid = 58, // PSN ticket was invalid
ExternalAccountAlreadyLinked = 59, // External account (PSN, Facebook...) is already linked to some other account, must explicitly request to replace/delete the link first
RemoteFileConflict = 60, // The sync cannot resume due to a conflict between the local and remote files
IllegalPassword = 61, // The requested new password is not legal
SameAsPreviousValue = 62, // new value is the same as the old one ( secret question and answer )
AccountLogonDenied = 63, // account login denied due to 2nd factor authentication failure
CannotUseOldPassword = 64, // The requested new password is not legal
InvalidLoginAuthCode = 65, // account login denied due to auth code invalid
AccountLogonDeniedNoMail = 66, // account login denied due to 2nd factor auth failure - and no mail has been sent
HardwareNotCapableOfIPT = 67, //
IPTInitError = 68, //
ParentalControlRestricted = 69, // operation failed due to parental control restrictions for current user
FacebookQueryError = 70, // Facebook query returned an error
ExpiredLoginAuthCode = 71, // account login denied due to auth code expired
IPLoginRestrictionFailed = 72,
AccountLockedDown = 73,
AccountLogonDeniedVerifiedEmailRequired = 74,
NoMatchingURL = 75,
BadResponse = 76, // parse failure, missing field, etc.
RequirePasswordReEntry = 77, // The user cannot complete the action until they re-enter their password
ValueOutOfRange = 78, // the value entered is outside the acceptable range
UnexpectedError = 79, // something happened that we didn't expect to ever happen
Disabled = 80, // The requested service has been configured to be unavailable
InvalidCEGSubmission = 81, // The set of files submitted to the CEG server are not valid !
RestrictedDevice = 82, // The device being used is not allowed to perform this action
RegionLocked = 83, // The action could not be complete because it is region restricted
RateLimitExceeded = 84, // Temporary rate limit exceeded, try again later, different from k_EResultLimitExceeded which may be permanent
AccountLoginDeniedNeedTwoFactor = 85, // Need two-factor code to login
ItemDeleted = 86, // The thing we're trying to access has been deleted
AccountLoginDeniedThrottle = 87, // login attempt failed, try to throttle response to possible attacker
TwoFactorCodeMismatch = 88, // two factor code mismatch
TwoFactorActivationCodeMismatch = 89, // activation code for two-factor didn't match
AccountAssociatedToMultiplePartners = 90, // account has been associated with multiple partners
NotModified = 91, // data not modified
NoMobileDevice = 92, // the account does not have a mobile device associated with it
TimeNotSynced = 93, // the time presented is out of range or tolerance
SmsCodeFailed = 94, // SMS code failure (no match, none pending, etc.)
AccountLimitExceeded = 95, // Too many accounts access this resource
AccountActivityLimitExceeded = 96, // Too many changes to this account
PhoneActivityLimitExceeded = 97, // Too many changes to this phone
RefundToWallet = 98, // Cannot refund to payment method, must use wallet
EmailSendFailure = 99, // Cannot send an email
NotSettled = 100, // Can't perform operation till payment has settled
NeedCaptcha = 101, // Needs to provide a valid captcha
GSLTDenied = 102, // a game server login token owned by this token's owner has been banned
GSOwnerDenied = 103, // game server owner is denied for other reason (account lock, community ban, vac ban, missing phone)
InvalidItemType = 104, // the type of thing we were requested to act on is invalid
IPBanned = 105, // the ip address has been banned from taking this action
};
}

View File

@ -0,0 +1,30 @@
using System;
namespace Steamworks
{
public class AuthTicket : IDisposable
{
public byte[] Data;
public uint Handle;
/// <summary>
/// Cancels a ticket.
/// You should cancel your ticket when you close the game or leave a server.
/// </summary>
public void Cancel()
{
if ( Handle != 0 )
{
SteamUser.Internal.CancelAuthTicket( Handle );
}
Handle = 0;
Data = null;
}
public void Dispose()
{
Cancel();
}
}
}

View File

@ -0,0 +1,120 @@
using Steamworks.Data;
using System;
using System.Runtime.InteropServices;
namespace Steamworks
{
public class ConnectionInterface
{
public Connection Connection;
public bool Connected = false;
public bool Connecting = true;
public string ConnectionName
{
get => Connection.ConnectionName;
set => Connection.ConnectionName = value;
}
public long UserData
{
get => Connection.UserData;
set => Connection.UserData = value;
}
public void Close() => Connection.Close();
public override string ToString() => Connection.ToString();
public virtual void OnConnectionChanged( ConnectionInfo data )
{
switch ( data.State )
{
case ConnectionState.Connecting:
OnConnecting( data );
break;
case ConnectionState.Connected:
OnConnected( data );
break;
case ConnectionState.ClosedByPeer:
case ConnectionState.ProblemDetectedLocally:
case ConnectionState.None:
OnDisconnected( data );
break;
}
}
/// <summary>
/// We're trying to connect!
/// </summary>
public virtual void OnConnecting( ConnectionInfo data )
{
Connecting = true;
}
/// <summary>
/// Client is connected. They move from connecting to Connections
/// </summary>
public virtual void OnConnected( ConnectionInfo data )
{
Connected = true;
Connecting = false;
}
/// <summary>
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
/// </summary>
public virtual void OnDisconnected( ConnectionInfo data )
{
Connected = false;
Connecting = false;
}
public void Receive( int bufferSize = 32 )
{
int processed = 0;
IntPtr messageBuffer = Marshal.AllocHGlobal( IntPtr.Size * bufferSize );
try
{
processed = SteamNetworkingSockets.Internal.ReceiveMessagesOnConnection( Connection, messageBuffer, bufferSize );
for ( int i = 0; i < processed; i++ )
{
ReceiveMessage( Marshal.ReadIntPtr( messageBuffer, i * IntPtr.Size ) );
}
}
finally
{
Marshal.FreeHGlobal( messageBuffer );
}
//
// Overwhelmed our buffer, keep going
//
if ( processed == bufferSize )
Receive( bufferSize );
}
internal unsafe void ReceiveMessage( IntPtr msgPtr )
{
var msg = Marshal.PtrToStructure<NetMsg>( msgPtr );
try
{
OnMessage( msg.DataPtr, msg.DataSize, msg.RecvTime, msg.MessageNumber, msg.Channel );
}
finally
{
//
// Releases the message
//
msg.Release( msgPtr );
}
}
public virtual void OnMessage( IntPtr data, int size, long messageNum, long recvTime, int channel )
{
}
}
}

View File

@ -0,0 +1,112 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Steamworks.Data;
namespace Steamworks
{
public class SocketInterface
{
public List<Connection> Connecting = new List<Connection>();
public List<Connection> Connected = new List<Connection>();
public Socket Socket { get; internal set; }
public bool Close() => Socket.Close();
public override string ToString() => Socket.ToString();
public virtual void OnConnectionChanged( Connection connection, ConnectionInfo data )
{
switch ( data.State )
{
case ConnectionState.Connecting:
OnConnecting( connection, data );
break;
case ConnectionState.Connected:
OnConnected( connection, data );
break;
case ConnectionState.ClosedByPeer:
case ConnectionState.ProblemDetectedLocally:
case ConnectionState.None:
OnDisconnected( connection, data );
break;
}
}
/// <summary>
/// Default behaviour is to accept every connection
/// </summary>
public virtual void OnConnecting( Connection connection, ConnectionInfo data )
{
connection.Accept();
Connecting.Add( connection );
}
/// <summary>
/// Client is connected. They move from connecting to Connections
/// </summary>
public virtual void OnConnected( Connection connection, ConnectionInfo data )
{
Connecting.Remove( connection );
Connected.Add( connection );
}
/// <summary>
/// The connection has been closed remotely or disconnected locally. Check data.State for details.
/// </summary>
public virtual void OnDisconnected( Connection connection, ConnectionInfo data )
{
connection.Close();
Connecting.Remove( connection );
Connected.Remove( connection );
}
public void Receive( int bufferSize = 32 )
{
int processed = 0;
IntPtr messageBuffer = Marshal.AllocHGlobal( IntPtr.Size * bufferSize );
try
{
processed = SteamNetworkingSockets.Internal.ReceiveMessagesOnListenSocket( Socket, messageBuffer, bufferSize );
for ( int i = 0; i < processed; i++ )
{
ReceiveMessage( Marshal.ReadIntPtr( messageBuffer, i * IntPtr.Size ) );
}
}
finally
{
Marshal.FreeHGlobal( messageBuffer );
}
//
// Overwhelmed our buffer, keep going
//
if ( processed == bufferSize )
Receive( bufferSize );
}
internal unsafe void ReceiveMessage( IntPtr msgPtr )
{
var msg = Marshal.PtrToStructure<NetMsg>( msgPtr );
try
{
OnMessage( msg.Connection, msg.Identity, msg.DataPtr, msg.DataSize, msg.RecvTime, msg.MessageNumber, msg.Channel );
}
finally
{
//
// Releases the message
//
msg.Release( msgPtr );
}
}
public virtual void OnMessage( Connection connection, NetIdentity identity, IntPtr data, int size, long messageNum, long recvTime, int channel )
{
}
}
}

View File

@ -1,298 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Facepunch.Steamworks
{
public partial class Client : BaseSteamworks
{
/// <summary>
/// A singleton accessor to get the current client instance.
/// </summary>
public static Client Instance { get; private set; }
/// <summary>
/// Current user's Username
/// </summary>
public string Username { get; private set; }
/// <summary>
/// Current user's SteamId
/// </summary>
public ulong SteamId { get; private set; }
/// <summary>
/// If we're sharing this game, this is the owner of it.
/// </summary>
public ulong OwnerSteamId { get; private set; }
/// <summary>
/// Current Beta name, if we're using a beta branch.
/// </summary>
public string BetaName { get; private set; }
/// <summary>
/// The BuildId of the current build
/// </summary>
public int BuildId { get; private set; }
/// <summary>
/// The folder in which this app is installed
/// </summary>
public DirectoryInfo InstallFolder { get; private set; }
/// <summary>
/// The currently selected language
/// </summary>
public string CurrentLanguage { get; }
/// <summary>
/// List of languages available to the game
/// </summary>
public string[] AvailableLanguages { get; }
public Voice Voice { get; private set; }
public ServerList ServerList { get; private set; }
public LobbyList LobbyList { get; private set; }
public App App { get; private set; }
public Achievements Achievements { get; private set; }
public Stats Stats { get; private set; }
public MicroTransactions MicroTransactions { get; private set; }
public User User { get; private set; }
public RemoteStorage RemoteStorage { get; private set; }
public Client( uint appId ) : base( appId )
{
if ( Instance != null )
{
throw new System.Exception( "Only one Facepunch.Steamworks.Client can exist - dispose the old one before trying to create a new one." );
}
Instance = this;
native = new Interop.NativeInterface();
//
// Get other interfaces
//
if ( !native.InitClient( this ) )
{
native.Dispose();
native = null;
Instance = null;
return;
}
//
// Register Callbacks
//
SteamNative.Callbacks.RegisterCallbacks( this );
//
// Setup interfaces that client and server both have
//
SetupCommonInterfaces();
//
// Client only interfaces
//
Voice = new Voice( this );
ServerList = new ServerList( this );
LobbyList = new LobbyList(this);
App = new App( this );
Stats = new Stats( this );
Achievements = new Achievements( this );
MicroTransactions = new MicroTransactions( this );
User = new User( this );
RemoteStorage = new RemoteStorage( this );
Workshop.friends = Friends;
Stats.UpdateStats();
//
// Cache common, unchanging info
//
AppId = appId;
Username = native.friends.GetPersonaName();
SteamId = native.user.GetSteamID();
BetaName = native.apps.GetCurrentBetaName();
OwnerSteamId = native.apps.GetAppOwner();
var appInstallDir = native.apps.GetAppInstallDir(AppId);
if (!String.IsNullOrEmpty(appInstallDir) && Directory.Exists(appInstallDir))
InstallFolder = new DirectoryInfo(appInstallDir);
BuildId = native.apps.GetAppBuildId();
CurrentLanguage = native.apps.GetCurrentGameLanguage();
AvailableLanguages = native.apps.GetAvailableGameLanguages().Split( new[] {';'}, StringSplitOptions.RemoveEmptyEntries ); // TODO: Assumed colon separated
//
// Run update, first call does some initialization
//
Update();
}
~Client()
{
Dispose();
}
/// <summary>
/// Should be called at least once every frame
/// </summary>
public override void Update()
{
if ( !IsValid )
return;
RunCallbacks();
Voice.Update();
Friends.Cycle();
base.Update();
}
/// <summary>
/// This is called in Update() - there's no need to call it manually unless you're running your own Update
/// </summary>
public void RunCallbacks()
{
native.api.SteamAPI_RunCallbacks();
}
/// <summary>
/// Call when finished to shut down the Steam client.
/// </summary>
public override void Dispose()
{
if ( disposed ) return;
if ( Voice != null )
{
Voice = null;
}
if ( ServerList != null )
{
ServerList.Dispose();
ServerList = null;
}
if (LobbyList != null)
{
LobbyList.Dispose();
LobbyList = null;
}
if ( App != null )
{
App.Dispose();
App = null;
}
if ( Stats != null )
{
Stats.Dispose();
Stats = null;
}
if ( Achievements != null )
{
Achievements.Dispose();
Achievements = null;
}
if ( MicroTransactions != null )
{
MicroTransactions.Dispose();
MicroTransactions = null;
}
if ( User != null )
{
User.Dispose();
User = null;
}
if ( RemoteStorage != null )
{
RemoteStorage.Dispose();
RemoteStorage = null;
}
if ( Instance == this )
{
Instance = null;
}
base.Dispose();
}
public enum LeaderboardSortMethod
{
None = 0,
Ascending = 1, // top-score is lowest number
Descending = 2, // top-score is highest number
};
// the display type (used by the Steam Community web site) for a leaderboard
public enum LeaderboardDisplayType
{
None = 0,
Numeric = 1, // simple numerical score
TimeSeconds = 2, // the score represents a time, in seconds
TimeMilliSeconds = 3, // the score represents a time, in milliseconds
};
public Leaderboard GetLeaderboard( string name, LeaderboardSortMethod sortMethod = LeaderboardSortMethod.None, LeaderboardDisplayType displayType = LeaderboardDisplayType.None )
{
var board = new Leaderboard( this );
native.userstats.FindOrCreateLeaderboard( name, (SteamNative.LeaderboardSortMethod)sortMethod, (SteamNative.LeaderboardDisplayType)displayType, board.OnBoardCreated );
return board;
}
/// <summary>
/// True if we're subscribed/authorised to be running this app
/// </summary>
public bool IsSubscribed => native.apps.BIsSubscribed();
/// <summary>
/// True if we're a cybercafe account
/// </summary>
public bool IsCybercafe => native.apps.BIsCybercafe();
/// <summary>
/// True if we're subscribed/authorised to be running this app, but only temporarily
/// due to a free weekend etc.
/// </summary>
public bool IsSubscribedFromFreeWeekend => native.apps.BIsSubscribedFromFreeWeekend();
/// <summary>
/// True if we're in low violence mode (germans are only allowed to see the insides of bodies in porn)
/// </summary>
public bool IsLowViolence => native.apps.BIsLowViolence();
/// <summary>
/// Checks if your executable was launched through Steam and relaunches it through Steam if it wasn't.
/// If this returns true then it starts the Steam client if required and launches your game again through it,
/// and you should quit your process as soon as possible. This effectively runs steam://run/AppId so it may
/// not relaunch the exact executable that called it, as it will always relaunch from the version installed
/// in your Steam library folder.
/// If it returns false, then your game was launched by the Steam client and no action needs to be taken.
/// One exception is if a steam_appid.txt file is present then this will return false regardless. This allows
/// you to develop and test without launching your game through the Steam client. Make sure to remove the
/// steam_appid.txt file when uploading the game to your Steam depot!
/// </summary>
public static bool RestartIfNecessary( uint appid )
{
using ( var api = new SteamNative.SteamApi() )
{
return api.SteamAPI_RestartAppIfNecessary( appid );
}
}
}
}

View File

@ -1,263 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public class Achievements : IDisposable
{
internal Client client;
public Achievement[] All { get; private set; }
public event Action OnUpdated;
public event Action<Achievement> OnAchievementStateChanged;
private List<Achievement> unlockedRecently = new List<Achievement>();
internal Achievements( Client c )
{
client = c;
All = new Achievement[0];
c.RegisterCallback<UserStatsReceived_t>( UserStatsReceived );
c.RegisterCallback<UserStatsStored_t>( UserStatsStored );
Refresh();
}
public void Refresh()
{
var old = All;
All = Enumerable.Range( 0, (int)client.native.userstats.GetNumAchievements() )
.Select( x =>
{
if ( old != null )
{
var name = client.native.userstats.GetAchievementName( (uint)x );
var found = old.FirstOrDefault( y => y.Id == name );
if ( found != null )
{
if ( found.Refresh() )
{
unlockedRecently.Add( found );
}
return found;
}
}
return new Achievement( client, x );
} )
.ToArray();
foreach ( var i in unlockedRecently )
{
OnUnlocked( i );
}
unlockedRecently.Clear();
}
internal void OnUnlocked( Achievement a )
{
OnAchievementStateChanged?.Invoke( a );
}
public void Dispose()
{
client = null;
}
/// <summary>
/// Find an achievement by name. Will be null if not found, or not ready.
/// </summary>
public Achievement Find( string identifier )
{
return All.FirstOrDefault( x => x.Id == identifier );
}
/// <summary>
/// Unlock an achievement by identifier. If apply is true this will happen as expected
/// and the achievement overlay will popup etc. If it's false then you'll have to manually
/// call Stats.StoreStats() to actually trigger it.
/// </summary>
public bool Trigger( string identifier, bool apply = true )
{
var a = Find( identifier );
if ( a == null ) return false;
return a.Trigger( apply );
}
/// <summary>
/// Reset an achievement by identifier
/// </summary>
public bool Reset( string identifier )
{
return client.native.userstats.ClearAchievement( identifier );
}
private void UserStatsReceived( UserStatsReceived_t stats )
{
if ( stats.GameID != client.AppId ) return;
Refresh();
OnUpdated?.Invoke();
}
private void UserStatsStored( UserStatsStored_t stats )
{
if ( stats.GameID != client.AppId ) return;
Refresh();
OnUpdated?.Invoke();
}
}
public class Achievement
{
private Client client;
public string Id { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
/// <summary>
/// True if unlocked
/// </summary>
public bool State { get; private set; }
/// <summary>
/// Should hold the unlock time if State is true
/// </summary>
public DateTime UnlockTime { get; private set; }
private int iconId { get; set; } = -1;
private int refreshCount = 0;
/// <summary>
/// Returns the percentage of users who have unlocked the specified achievement, or -1 if no data available.
/// </summary>
public float GlobalUnlockedPercentage
{
get
{
if ( State )
return 1;
float pct = 0;
if ( !client.native.userstats.GetAchievementAchievedPercent( Id, out pct ) )
return -1.0f;
return pct;
}
}
private Image _icon;
public Image Icon
{
get
{
if ( iconId <= 0 ) return null;
if ( _icon == null )
{
_icon = new Image();
_icon.Id = iconId;
}
if ( _icon.IsLoaded )
return _icon;
if ( !_icon.TryLoad( client.native.utils ) )
return null;
return _icon;
}
}
public Achievement( Client client, int index )
{
this.client = client;
Id = client.native.userstats.GetAchievementName( (uint) index );
Name = client.native.userstats.GetAchievementDisplayAttribute( Id, "name" );
Description = client.native.userstats.GetAchievementDisplayAttribute( Id, "desc" );
iconId = client.native.userstats.GetAchievementIcon( Id );
Refresh();
}
/// <summary>
/// Make this achievement earned
/// </summary>
public bool Trigger( bool apply = true )
{
if ( State )
return false;
State = true;
UnlockTime = DateTime.Now;
var r = client.native.userstats.SetAchievement( Id );
if ( apply )
{
client.Stats.StoreStats();
}
client.Achievements.OnUnlocked( this );
return r;
}
/// <summary>
/// Reset this achievement to not achieved
/// </summary>
public bool Reset()
{
State = false;
UnlockTime = DateTime.Now;
return client.native.userstats.ClearAchievement( Id );
}
/// <summary>
/// Refresh the unlock state. You shouldn't need to call this manually
/// but it's here if you have to for some reason. Retuns true if state changed (meaning, probably unlocked)
/// </summary>
public bool Refresh()
{
bool previousState = State;
bool state = false;
uint unlockTime;
State = false;
if ( client.native.userstats.GetAchievementAndUnlockTime( Id, ref state, out unlockTime ) )
{
State = state;
UnlockTime = Utility.Epoch.ToDateTime( unlockTime );
}
refreshCount++;
if ( previousState != State && refreshCount > 1 )
{
return true;
}
return false;
}
}
}

View File

@ -1,131 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public class App : IDisposable
{
internal Client client;
internal App( Client c )
{
client = c;
client.RegisterCallback<SteamNative.DlcInstalled_t>( DlcInstalled );
}
public delegate void DlcInstalledDelegate( uint appid );
/// <summary>
/// Triggered after the current user gains ownership of DLC and that DLC is installed.
/// </summary>
public event DlcInstalledDelegate OnDlcInstalled;
private void DlcInstalled( DlcInstalled_t data )
{
if ( OnDlcInstalled != null )
{
OnDlcInstalled( data.AppID );
}
}
public void Dispose()
{
client = null;
}
/// <summary>
/// Mark the content as corrupt, so it will validate the downloaded files
/// once the app is closed. This is good to call when you detect a crash happening
/// or a file is missing that is meant to be there.
/// </summary>
public void MarkContentCorrupt( bool missingFilesOnly = false )
{
client.native.apps.MarkContentCorrupt( missingFilesOnly );
}
/// <summary>
/// Tell steam to install the Dlc specified by the AppId
/// </summary>
public void InstallDlc( uint appId )
{
client.native.apps.InstallDLC( appId );
}
/// <summary>
/// Tell steam to uninstall the Dlc specified by the AppId
/// </summary>
public void UninstallDlc(uint appId)
{
client.native.apps.UninstallDLC( appId );
}
/// <summary>
/// Get the purchase time for this appid. Will return DateTime.MinValue if none.
/// </summary>
public DateTime PurchaseTime(uint appId)
{
var time = client.native.apps.GetEarliestPurchaseUnixTime(appId);
if ( time == 0 ) return DateTime.MinValue;
return Utility.Epoch.ToDateTime( time );
}
/// <summary>
/// Checks if the active user is subscribed to a specified AppId.
/// Only use this if you need to check ownership of another game related to yours, a demo for example.
/// </summary>
public bool IsSubscribed(uint appId)
{
return client.native.apps.BIsSubscribedApp(appId);
}
/// <summary>
/// Returns true if specified app is installed.
/// </summary>
public bool IsInstalled(uint appId)
{
return client.native.apps.BIsAppInstalled(appId);
}
/// <summary>
/// Returns true if specified app is installed.
/// </summary>
public bool IsDlcInstalled( uint appId )
{
return client.native.apps.BIsDlcInstalled( appId );
}
/// <summary>
/// Returns the appid's name
/// Returns error if the current app Id does not have permission to use this interface
/// </summary>
public string GetName( uint appId )
{
var str = client.native.applist.GetAppName( appId );
if ( str == null ) return "error";
return str;
}
/// <summary>
/// Returns the app's install folder
/// Returns error if the current app Id does not have permission to use this interface
/// </summary>
public string GetInstallFolder( uint appId )
{
return client.native.applist.GetAppInstallDir( appId );
}
/// <summary>
/// Returns the app's current build id
/// Returns 0 if the current app Id does not have permission to use this interface
/// </summary>
public int GetBuildId( uint appId )
{
return client.native.applist.GetAppBuildId( appId );
}
}
}

View File

@ -1,82 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public partial class Client : IDisposable
{
Auth _auth;
public Auth Auth
{
get
{
if ( _auth == null )
_auth = new Auth{ client = this };
return _auth;
}
}
}
public class Auth
{
internal Client client;
public class Ticket : IDisposable
{
internal Client client;
public byte[] Data;
public uint Handle;
/// <summary>
/// Cancels a ticket.
/// You should cancel your ticket when you close the game or leave a server.
/// </summary>
public void Cancel()
{
if ( client.IsValid && Handle != 0 )
{
client.native.user.CancelAuthTicket( Handle );
Handle = 0;
Data = null;
}
}
public void Dispose()
{
Cancel();
}
}
/// <summary>
/// Creates an auth ticket.
/// Which you can send to a server to authenticate that you are who you say you are.
/// </summary>
public unsafe Ticket GetAuthSessionTicket()
{
var data = new byte[1024];
fixed ( byte* b = data )
{
uint ticketLength = 0;
uint ticket = client.native.user.GetAuthSessionTicket( (IntPtr) b, data.Length, out ticketLength );
if ( ticket == 0 )
return null;
return new Ticket()
{
client = client,
Data = data.Take( (int)ticketLength ).ToArray(),
Handle = ticket
};
}
}
}
}

View File

@ -1,383 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public partial class Client : IDisposable
{
Friends _friends;
public Friends Friends
{
get
{
if ( _friends == null )
_friends = new Friends( this );
return _friends;
}
}
}
/// <summary>
/// Handles most interactions with people in Steam, not just friends as the name would suggest.
/// </summary>
/// <example>
/// foreach ( var friend in client.Friends.AllFriends )
/// {
/// Console.WriteLine( $"{friend.Id}: {friend.Name}" );
/// }
/// </example>
public class Friends
{
internal Client client;
private byte[] buffer = new byte[1024 * 128];
internal Friends( Client c )
{
client = c;
client.RegisterCallback<AvatarImageLoaded_t>( OnAvatarImageLoaded );
client.RegisterCallback<PersonaStateChange_t>( OnPersonaStateChange );
client.RegisterCallback<GameRichPresenceJoinRequested_t>( OnGameJoinRequested );
client.RegisterCallback<GameConnectedFriendChatMsg_t>( OnFriendChatMessage );
}
public delegate void ChatMessageDelegate( SteamFriend friend, string type, string message );
/// <summary>
/// Called when chat message has been received from a friend. You'll need to turn on
/// ListenForFriendsMessages to recieve this.
/// </summary>
public event ChatMessageDelegate OnChatMessage;
private unsafe void OnFriendChatMessage( GameConnectedFriendChatMsg_t data )
{
if ( OnChatMessage == null ) return;
var friend = Get( data.SteamIDUser );
var type = ChatEntryType.ChatMsg;
fixed ( byte* ptr = buffer )
{
var len = client.native.friends.GetFriendMessage( data.SteamIDUser, data.MessageID, (IntPtr)ptr, buffer.Length, out type );
if ( len == 0 && type == ChatEntryType.Invalid )
return;
var typeName = type.ToString();
var message = Encoding.UTF8.GetString( buffer, 0, len );
OnChatMessage( friend, typeName, message );
}
}
private bool _listenForFriendsMessages;
/// <summary>
/// Listens for Steam friends chat messages.
/// You can then show these chats inline in the game. For example with a Blizzard style chat message system or the chat system in Dota 2.
/// After enabling this you will receive callbacks when ever the user receives a chat message.
/// </summary>
public bool ListenForFriendsMessages
{
get
{
return _listenForFriendsMessages;
}
set
{
_listenForFriendsMessages = value;
client.native.friends.SetListenForFriendsMessages( value );
}
}
public delegate void JoinRequestedDelegate( SteamFriend friend, string connect );
//
// Called when a friend has invited you to their game (using InviteToGame)
//
public event JoinRequestedDelegate OnInvitedToGame;
private void OnGameJoinRequested( GameRichPresenceJoinRequested_t data )
{
if ( OnInvitedToGame != null )
{
OnInvitedToGame( Get( data.SteamIDFriend ), data.Connect );
}
}
/// <summary>
/// Try to get information about this user - which as name and avatar.
/// If returns true, we already have this user's information.
/// </summary>
public bool UpdateInformation( ulong steamid )
{
return !client.native.friends.RequestUserInformation( steamid, false );
}
/// <summary>
/// Get this user's name
/// </summary>
public string GetName( ulong steamid )
{
client.native.friends.RequestUserInformation( steamid, true );
return client.native.friends.GetFriendPersonaName( steamid );
}
private List<SteamFriend> _allFriends;
/// <summary>
/// Returns all friends, even blocked, ignored, friend requests etc
/// </summary>
public IEnumerable<SteamFriend> All
{
get
{
if ( _allFriends == null )
{
_allFriends = new List<SteamFriend>();
Refresh();
}
return _allFriends;
}
}
/// <summary>
/// Returns only friends
/// </summary>
public IEnumerable<SteamFriend> AllFriends
{
get
{
foreach ( var friend in All )
{
if ( !friend.IsFriend ) continue;
yield return friend;
}
}
}
/// <summary>
/// Returns all blocked users
/// </summary>
public IEnumerable<SteamFriend> AllBlocked
{
get
{
foreach ( var friend in All )
{
if ( !friend.IsBlocked ) continue;
yield return friend;
}
}
}
public void Refresh()
{
if ( _allFriends == null )
{
_allFriends = new List<SteamFriend>();
}
_allFriends.Clear();
var flags = (int) SteamNative.FriendFlags.All;
var count = client.native.friends.GetFriendCount( flags );
for ( int i=0; i<count; i++ )
{
var steamid = client.native.friends.GetFriendByIndex( i, flags );
_allFriends.Add( Get( steamid ) );
}
}
public enum AvatarSize
{
/// <summary>
/// Should be 32x32 - but make sure to check!
/// </summary>
Small,
/// <summary>
/// Should be 64x64 - but make sure to check!
/// </summary>
Medium,
/// <summary>
/// Should be 184x184 - but make sure to check!
/// </summary>
Large
}
/// <summary>
/// Try to get the avatar immediately. This should work for people on your friends list.
/// </summary>
public Image GetCachedAvatar( AvatarSize size, ulong steamid )
{
var imageid = 0;
switch (size)
{
case AvatarSize.Small:
imageid = client.native.friends.GetSmallFriendAvatar(steamid);
break;
case AvatarSize.Medium:
imageid = client.native.friends.GetMediumFriendAvatar(steamid);
break;
case AvatarSize.Large:
imageid = client.native.friends.GetLargeFriendAvatar(steamid);
break;
}
if ( imageid == 1 ) return null; // Placeholder large
if ( imageid == 2 ) return null; // Placeholder medium
if ( imageid == 3 ) return null; // Placeholder small
var img = new Image()
{
Id = imageid
};
if ( !img.TryLoad( client.native.utils ) )
return null;
return img;
}
/// <summary>
/// Callback will be called when the avatar is ready. If we fail to get an
/// avatar, might be called with a null Image.
/// </summary>
public void GetAvatar( AvatarSize size, ulong steamid, Action<Image> callback )
{
// Maybe we already have it downloaded?
var image = GetCachedAvatar(size, steamid);
if ( image != null )
{
callback(image);
return;
}
// Lets request it from Steam
if (!client.native.friends.RequestUserInformation(steamid, false))
{
// Steam told us to get fucked
callback(null);
return;
}
PersonaCallbacks.Add( new PersonaCallback
{
SteamId = steamid,
Size = size,
Callback = callback,
Time = DateTime.Now
});
}
private class PersonaCallback
{
public ulong SteamId;
public AvatarSize Size;
public Action<Image> Callback;
public DateTime Time;
}
List<PersonaCallback> PersonaCallbacks = new List<PersonaCallback>();
public SteamFriend Get( ulong steamid )
{
var friend = All.Where( x => x.Id == steamid ).FirstOrDefault();
if ( friend != null ) return friend;
var f = new SteamFriend()
{
Id = steamid,
Client = client
};
f.Refresh();
return f;
}
internal void Cycle()
{
if ( PersonaCallbacks.Count == 0 ) return;
var timeOut = DateTime.Now.AddSeconds( -10 );
for ( int i = PersonaCallbacks.Count-1; i >= 0; i-- )
{
var cb = PersonaCallbacks[i];
// Timeout
if ( cb.Time < timeOut )
{
if ( cb.Callback != null )
{
cb.Callback( null );
}
PersonaCallbacks.Remove( cb );
continue;
}
}
}
private void OnPersonaStateChange( PersonaStateChange_t data )
{
// k_EPersonaChangeAvatar
if ( (data.ChangeFlags & 0x0040) == 0x0040 )
{
LoadAvatarForSteamId( data.SteamID );
}
//
// Find and refresh this friend's status
//
foreach ( var friend in All )
{
if ( friend.Id != data.SteamID ) continue;
friend.Refresh();
}
}
void LoadAvatarForSteamId( ulong Steamid )
{
for ( int i = PersonaCallbacks.Count - 1; i >= 0; i-- )
{
var cb = PersonaCallbacks[i];
if ( cb.SteamId != Steamid ) continue;
var image = GetCachedAvatar( cb.Size, cb.SteamId );
if ( image == null ) continue;
PersonaCallbacks.Remove( cb );
if ( cb.Callback != null )
{
cb.Callback( image );
}
}
}
private void OnAvatarImageLoaded( AvatarImageLoaded_t data )
{
LoadAvatarForSteamId( data.SteamID );
}
}
}

View File

@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public class Image
{
public int Id { get; internal set; }
public int Width { get; internal set; }
public int Height { get; internal set; }
public byte[] Data { get; internal set; }
public bool IsLoaded { get; internal set; }
/// <summary>
/// Return true if this image couldn't be loaded for some reason
/// </summary>
public bool IsError { get; internal set; }
unsafe internal bool TryLoad( SteamNative.SteamUtils utils )
{
if ( IsLoaded ) return true;
uint width = 0, height = 0;
if ( utils.GetImageSize( Id, out width, out height ) == false )
{
IsError = true;
return false;
}
var buffer = new byte[ width * height * 4 ];
fixed ( byte* ptr = buffer )
{
if ( utils.GetImageRGBA( Id, (IntPtr) ptr, buffer.Length ) == false )
{
IsError = true;
return false;
}
}
Width = (int) width;
Height = (int) height;
Data = buffer;
IsLoaded = true;
IsError = false;
return true;
}
public Color GetPixel( int x, int y )
{
if ( !IsLoaded ) throw new System.Exception( "Image not loaded" );
if ( x < 0 || x >= Width ) throw new System.Exception( "x out of bounds" );
if ( y < 0 || y >= Height ) throw new System.Exception( "y out of bounds" );
Color c = new Color();
var i = ( y * Width + x ) * 4;
c.r = Data[i + 0];
c.g = Data[i + 1];
c.b = Data[i + 2];
c.a = Data[i + 3];
return c;
}
}
public struct Color
{
public byte r, g, b, a;
}
}

View File

@ -1,355 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Facepunch.Steamworks.Callbacks;
using SteamNative;
using Result = SteamNative.Result;
namespace Facepunch.Steamworks
{
public class Leaderboard : IDisposable
{
/// <summary>
/// Type of leaderboard request
/// </summary>
public enum RequestType
{
/// <summary>
/// Query everyone and everything
/// </summary>
Global = LeaderboardDataRequest.Global,
/// <summary>
/// Query entries near to this user's rank
/// </summary>
GlobalAroundUser = LeaderboardDataRequest.GlobalAroundUser,
/// <summary>
/// Only show friends of this user
/// </summary>
Friends = LeaderboardDataRequest.Friends
}
private static readonly int[] subEntriesBuffer = new int[512];
internal ulong BoardId;
internal Client client;
private readonly Queue<Action> _onCreated = new Queue<Action>();
/// <summary>
/// The results from the last query. Can be null.
/// </summary>
public Entry[] Results;
internal Leaderboard( Client c )
{
client = c;
}
/// <summary>
/// The name of this board, as retrieved from Steam
/// </summary>
public string Name { get; private set; }
/// <summary>
/// The total number of entries on this board
/// </summary>
public int TotalEntries { get; private set; }
/// <summary>
/// Returns true if this board is valid, ie, we've received
/// a positive response from Steam about it.
/// </summary>
public bool IsValid => BoardId != 0;
/// <summary>
/// Returns true if we asked steam about this board but it returned
/// an error.
/// </summary>
public bool IsError { get; private set; }
/// <summary>
/// Returns true if we're querying scores
/// </summary>
public bool IsQuerying { get; private set; }
public void Dispose()
{
client = null;
}
private void DispatchOnCreatedCallbacks()
{
while ( _onCreated.Count > 0 )
{
_onCreated.Dequeue()();
}
}
private bool DeferOnCreated( Action onValid, FailureCallback onFailure = null )
{
if ( IsValid || IsError ) return false;
_onCreated.Enqueue( () =>
{
if ( IsValid ) onValid();
else onFailure?.Invoke( Callbacks.Result.Fail );
} );
return true;
}
/// <summary>
/// Called when the leaderboard information is successfully recieved from Steam
/// </summary>
public Action OnBoardInformation;
internal void OnBoardCreated( LeaderboardFindResult_t result, bool error )
{
Console.WriteLine( $"result.LeaderboardFound: {result.LeaderboardFound}" );
Console.WriteLine( $"result.SteamLeaderboard: {result.SteamLeaderboard}" );
if ( error || ( result.LeaderboardFound == 0 ) )
{
IsError = true;
}
else
{
BoardId = result.SteamLeaderboard;
if ( IsValid )
{
Name = client.native.userstats.GetLeaderboardName( BoardId );
TotalEntries = client.native.userstats.GetLeaderboardEntryCount( BoardId );
OnBoardInformation?.Invoke();
}
}
DispatchOnCreatedCallbacks();
}
/// <summary>
/// Add a score to this leaderboard.
/// Subscores are totally optional, and can be used for other game defined data such as laps etc.. although
/// they have no bearing on sorting at all
/// If onlyIfBeatsOldScore is true, the score will only be updated if it beats the existing score, else it will always
/// be updated. Beating the existing score is subjective - and depends on how your leaderboard was set up as to whether
/// that means higher or lower.
/// </summary>
public bool AddScore( bool onlyIfBeatsOldScore, int score, params int[] subscores )
{
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => AddScore( onlyIfBeatsOldScore, score, subscores ) );
var flags = LeaderboardUploadScoreMethod.ForceUpdate;
if ( onlyIfBeatsOldScore ) flags = LeaderboardUploadScoreMethod.KeepBest;
client.native.userstats.UploadLeaderboardScore( BoardId, flags, score, subscores, subscores.Length );
return true;
}
/// <summary>
/// Callback invoked by <see cref="AddScore(bool, int, int[], AddScoreCallback, FailureCallback)"/> when score submission
/// is complete.
/// </summary>
/// <param name="result">If successful, information about the new entry</param>
public delegate void AddScoreCallback( AddScoreResult result );
/// <summary>
/// Information about a newly submitted score.
/// </summary>
public struct AddScoreResult
{
public int Score;
public bool ScoreChanged;
public int GlobalRankNew;
public int GlobalRankPrevious;
}
/// <summary>
/// Add a score to this leaderboard.
/// Subscores are totally optional, and can be used for other game defined data such as laps etc.. although
/// they have no bearing on sorting at all
/// If onlyIfBeatsOldScore is true, the score will only be updated if it beats the existing score, else it will always
/// be updated.
/// Information about the newly submitted score is passed to the optional <paramref name="onSuccess"/>.
/// </summary>
public bool AddScore( bool onlyIfBeatsOldScore, int score, int[] subscores = null, AddScoreCallback onSuccess = null, FailureCallback onFailure = null )
{
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => AddScore( onlyIfBeatsOldScore, score, subscores, onSuccess, onFailure ), onFailure );
if ( subscores == null ) subscores = new int[0];
var flags = LeaderboardUploadScoreMethod.ForceUpdate;
if ( onlyIfBeatsOldScore ) flags = LeaderboardUploadScoreMethod.KeepBest;
client.native.userstats.UploadLeaderboardScore( BoardId, flags, score, subscores, subscores.Length, ( result, error ) =>
{
if ( !error && result.Success != 0 )
{
onSuccess?.Invoke( new AddScoreResult
{
Score = result.Score,
ScoreChanged = result.ScoreChanged != 0,
GlobalRankNew = result.GlobalRankNew,
GlobalRankPrevious = result.GlobalRankPrevious
} );
}
else
{
onFailure?.Invoke( error ? Callbacks.Result.IOFailure : Callbacks.Result.Fail );
}
} );
return true;
}
/// <summary>
/// Callback invoked by <see cref="Leaderboard.AttachRemoteFile"/> when file attachment is complete.
/// </summary>
public delegate void AttachRemoteFileCallback();
/// <summary>
/// Attempt to attach a <see cref="RemoteStorage"/> file to the current user's leaderboard entry.
/// Can be useful for storing replays along with scores.
/// </summary>
/// <returns>True if the file attachment process has started</returns>
public bool AttachRemoteFile( RemoteFile file, AttachRemoteFileCallback onSuccess = null, FailureCallback onFailure = null )
{
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => AttachRemoteFile( file, onSuccess, onFailure ), onFailure );
if ( file.IsShared )
{
var handle = client.native.userstats.AttachLeaderboardUGC( BoardId, file.UGCHandle, ( result, error ) =>
{
if ( !error && result.Result == Result.OK )
{
onSuccess?.Invoke();
}
else
{
onFailure?.Invoke( result.Result == 0 ? Callbacks.Result.IOFailure : (Callbacks.Result) result.Result );
}
} );
return handle.IsValid;
}
file.Share( () =>
{
if ( !file.IsShared || !AttachRemoteFile( file, onSuccess, onFailure ) )
{
onFailure?.Invoke( Callbacks.Result.Fail );
}
}, onFailure );
return true;
}
/// <summary>
/// Fetch a subset of scores. The scores end up in Results.
/// </summary>
/// <returns>Returns true if we have started the query</returns>
public bool FetchScores( RequestType RequestType, int start, int end )
{
if ( !IsValid ) return false;
if ( IsQuerying ) return false;
client.native.userstats.DownloadLeaderboardEntries( BoardId, (LeaderboardDataRequest) RequestType, start, end, OnScores );
Results = null;
IsQuerying = true;
return true;
}
private unsafe void ReadScores( LeaderboardScoresDownloaded_t result, List<Entry> dest )
{
for ( var i = 0; i < result.CEntryCount; i++ )
fixed ( int* ptr = subEntriesBuffer )
{
var entry = new LeaderboardEntry_t();
if ( client.native.userstats.GetDownloadedLeaderboardEntry( result.SteamLeaderboardEntries, i, ref entry, (IntPtr) ptr, subEntriesBuffer.Length ) )
dest.Add( new Entry
{
GlobalRank = entry.GlobalRank,
Score = entry.Score,
SteamId = entry.SteamIDUser,
SubScores = entry.CDetails == 0 ? null : subEntriesBuffer.Take( entry.CDetails ).ToArray(),
Name = client.Friends.GetName( entry.SteamIDUser ),
AttachedFile = (entry.UGC >> 32) == 0xffffffff ? null : new RemoteFile( client.RemoteStorage, entry.UGC )
} );
}
}
[ThreadStatic] private static List<Entry> _sEntryBuffer;
/// <summary>
/// Callback invoked by <see cref="FetchScores(RequestType, int, int, FetchScoresCallback, FailureCallback)"/> when
/// a query is complete.
/// </summary>
public delegate void FetchScoresCallback( Entry[] results );
/// <summary>
/// Fetch a subset of scores. The scores are passed to <paramref name="onSuccess"/>.
/// </summary>
/// <returns>Returns true if we have started the query</returns>
public bool FetchScores( RequestType RequestType, int start, int end, FetchScoresCallback onSuccess, FailureCallback onFailure = null )
{
if ( IsError ) return false;
if ( !IsValid ) return DeferOnCreated( () => FetchScores( RequestType, start, end, onSuccess, onFailure ), onFailure );
client.native.userstats.DownloadLeaderboardEntries( BoardId, (LeaderboardDataRequest) RequestType, start, end, ( result, error ) =>
{
if ( error )
{
onFailure?.Invoke( Callbacks.Result.IOFailure );
}
else
{
if ( _sEntryBuffer == null ) _sEntryBuffer = new List<Entry>();
else _sEntryBuffer.Clear();
ReadScores( result, _sEntryBuffer );
onSuccess( _sEntryBuffer.ToArray() );
}
} );
return true;
}
private void OnScores( LeaderboardScoresDownloaded_t result, bool error )
{
IsQuerying = false;
if ( client == null ) return;
if ( error ) return;
var list = new List<Entry>();
ReadScores( result, list );
Results = list.ToArray();
}
/// <summary>
/// A single entry in a leaderboard
/// </summary>
public struct Entry
{
public ulong SteamId;
public int Score;
public int[] SubScores;
public int GlobalRank;
public RemoteFile AttachedFile;
/// <summary>
/// Note that the player's name might not be immediately available.
/// If that's the case you'll have to use Friends.GetName to find the name
/// </summary>
public string Name;
}
}
}

View File

@ -1,112 +0,0 @@
using System.Collections.Generic;
namespace Facepunch.Steamworks
{
public partial class Lobby
{
/// <summary>
/// Class to hold global lobby data. This is stuff like maps/modes/etc. Data set here can be filtered by LobbyList.
/// </summary>
public class LobbyData
{
internal Client client;
internal ulong lobby;
internal Dictionary<string, string> data;
public LobbyData( Client c, ulong l )
{
client = c;
lobby = l;
data = new Dictionary<string, string>();
}
/// <summary>
/// Get the lobby value for the specific key
/// </summary>
/// <param name="k">The key to find</param>
/// <returns>The value at key</returns>
public string GetData( string k )
{
if ( data.ContainsKey( k ) )
{
return data[k];
}
return "ERROR: key not found";
}
/// <summary>
/// Get a list of all the data in the Lobby
/// </summary>
/// <returns>Dictionary of all the key/value pairs in the data</returns>
public Dictionary<string, string> GetAllData()
{
Dictionary<string, string> returnData = new Dictionary<string, string>();
foreach ( KeyValuePair<string, string> item in data )
{
returnData.Add( item.Key, item.Value );
}
return returnData;
}
/// <summary>
/// Set the value for specified Key. Note that the keys "joinable", "appid", "name", and "lobbytype" are reserved for internal library use.
/// </summary>
/// <param name="k">The key to set the value for</param>
/// <param name="v">The value of the Key</param>
/// <returns>True if data successfully set</returns>
public bool SetData( string k, string v )
{
if ( data.ContainsKey( k ) )
{
if ( data[k] == v ) { return true; }
if ( client.native.matchmaking.SetLobbyData( lobby, k, v ) )
{
data[k] = v;
return true;
}
}
else
{
if ( client.native.matchmaking.SetLobbyData( lobby, k, v ) )
{
data.Add( k, v );
return true;
}
}
return false;
}
/// <summary>
/// Remove the key from the LobbyData. Note that the keys "joinable", "appid", "name", and "lobbytype" are reserved for internal library use.
/// </summary>
/// <param name="k">The key to remove</param>
/// <returns>True if Key successfully removed</returns>
public bool RemoveData( string k )
{
if ( data.ContainsKey( k ) )
{
if ( client.native.matchmaking.DeleteLobbyData( lobby, k ) )
{
data.Remove( k );
return true;
}
}
return false;
}
}
/*not implemented
//set the game server of the lobby
client.native.matchmaking.GetLobbyGameServer;
client.native.matchmaking.SetLobbyGameServer;
//used with game server stuff
SteamNative.LobbyGameCreated_t
*/
}
}

View File

@ -1,599 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public partial class Client : IDisposable
{
Lobby _lobby;
public Lobby Lobby
{
get
{
if ( _lobby == null )
_lobby = new Steamworks.Lobby( this );
return _lobby;
}
}
}
public partial class Lobby : IDisposable
{
//The type of lobby you are creating
public enum Type : int
{
Private = SteamNative.LobbyType.Private,
FriendsOnly = SteamNative.LobbyType.FriendsOnly,
Public = SteamNative.LobbyType.Public,
Invisible = SteamNative.LobbyType.Invisible,
Error //happens if you try to get this when you aren't in a valid lobby
}
internal Client client;
public Lobby( Client c )
{
client = c;
// For backwards compatibility
OnLobbyJoinRequested = Join;
client.RegisterCallback<SteamNative.LobbyDataUpdate_t>( OnLobbyDataUpdatedAPI );
client.RegisterCallback<SteamNative.LobbyChatMsg_t>( OnLobbyChatMessageRecievedAPI );
client.RegisterCallback<SteamNative.LobbyChatUpdate_t>( OnLobbyStateUpdatedAPI );
client.RegisterCallback<SteamNative.GameLobbyJoinRequested_t>( OnLobbyJoinRequestedAPI );
client.RegisterCallback<SteamNative.LobbyInvite_t>( OnUserInvitedToLobbyAPI );
client.RegisterCallback<SteamNative.PersonaStateChange_t>( OnLobbyMemberPersonaChangeAPI );
}
/// <summary>
/// The CSteamID of the lobby we're currently in.
/// </summary>
public ulong CurrentLobby { get; private set; }
/// <summary>
/// The LobbyData of the CurrentLobby. Note this is the global data for the lobby. Use SetMemberData to set specific member data.
/// </summary>
public LobbyData CurrentLobbyData { get; private set; }
/// <summary>
/// Returns true if this lobby is valid, ie, we've succesffuly created and/or joined a lobby.
/// </summary>
public bool IsValid => CurrentLobby != 0;
/// <summary>
/// Join a Lobby through its LobbyID. OnLobbyJoined is called with the result of the Join attempt.
/// </summary>
/// <param name="lobbyID">CSteamID of lobby to join</param>
public void Join( ulong lobbyID )
{
Leave();
client.native.matchmaking.JoinLobby( lobbyID, OnLobbyJoinedAPI );
}
void OnLobbyJoinedAPI( LobbyEnter_t callback, bool error )
{
if ( error || (callback.EChatRoomEnterResponse != (uint)(SteamNative.ChatRoomEnterResponse.Success)) )
{
if ( OnLobbyJoined != null ) { OnLobbyJoined( false ); }
return;
}
CurrentLobby = callback.SteamIDLobby;
UpdateLobbyData();
if ( OnLobbyJoined != null ) { OnLobbyJoined( true ); }
}
/// <summary>
/// Called when a lobby has been attempted joined. Returns true if lobby was successfuly joined, false if not.
/// </summary>
public Action<bool> OnLobbyJoined;
/// <summary>
/// Creates a lobby and returns the created lobby. You auto join the created lobby. The lobby is stored in Client.Lobby.CurrentLobby if successful.
/// </summary>
/// <param name="lobbyType">The Lobby.Type of Lobby to be created</param>
/// <param name="maxMembers">The maximum amount of people you want to be able to be in this lobby, including yourself</param>
public void Create( Lobby.Type lobbyType, int maxMembers )
{
client.native.matchmaking.CreateLobby( (SteamNative.LobbyType)lobbyType, maxMembers, OnLobbyCreatedAPI );
createdLobbyType = lobbyType;
}
internal Type createdLobbyType;
internal void OnLobbyCreatedAPI( LobbyCreated_t callback, bool error )
{
//from SpaceWarClient.cpp 793
if ( error || (callback.Result != Result.OK) )
{
if ( OnLobbyCreated != null ) { OnLobbyCreated( false ); }
return;
}
//set owner specific properties
Owner = client.SteamId;
CurrentLobby = callback.SteamIDLobby;
CurrentLobbyData = new LobbyData( client, CurrentLobby );
Name = client.Username + "'s Lobby";
CurrentLobbyData.SetData( "appid", client.AppId.ToString() );
LobbyType = createdLobbyType;
CurrentLobbyData.SetData( "lobbytype", LobbyType.ToString() );
Joinable = true;
if ( OnLobbyCreated != null ) { OnLobbyCreated( true ); }
}
/// <summary>
/// Callback for when lobby is created. Parameter resolves true when the Lobby was successfully created
/// </summary>
public Action<bool> OnLobbyCreated;
/// <summary>
/// Sets user data for the Lobby. Things like Character, Skin, Ready, etc. Can only set your own member data
/// </summary>
public void SetMemberData( string key, string value )
{
if ( CurrentLobby == 0 ) { return; }
client.native.matchmaking.SetLobbyMemberData( CurrentLobby, key, value );
}
/// <summary>
/// Get the per-user metadata from this lobby. Can get data from any user
/// </summary>
/// <param name="steamID">ulong SteamID of the user you want to get data from</param>
/// <param name="key">String key of the type of data you want to get</param>
/// <returns></returns>
public string GetMemberData( ulong steamID, string key )
{
if ( CurrentLobby == 0 ) { return "ERROR: NOT IN ANY LOBBY"; }
return client.native.matchmaking.GetLobbyMemberData( CurrentLobby, steamID, key );
}
internal void OnLobbyDataUpdatedAPI( LobbyDataUpdate_t callback )
{
if ( callback.SteamIDLobby != CurrentLobby ) return;
if ( callback.SteamIDLobby == CurrentLobby ) //actual lobby data was updated by owner
{
UpdateLobbyData();
}
if ( UserIsInCurrentLobby( callback.SteamIDMember ) ) //some member of this lobby updated their information
{
if ( OnLobbyMemberDataUpdated != null ) { OnLobbyMemberDataUpdated( callback.SteamIDMember ); }
}
}
/// <summary>
/// Updates the LobbyData property to have the data for the current lobby, if any
/// </summary>
internal void UpdateLobbyData()
{
int dataCount = client.native.matchmaking.GetLobbyDataCount( CurrentLobby );
CurrentLobbyData = new LobbyData( client, CurrentLobby );
for ( int i = 0; i < dataCount; i++ )
{
if ( client.native.matchmaking.GetLobbyDataByIndex( CurrentLobby, i, out string key, out string value ) )
{
CurrentLobbyData.SetData( key, value );
}
}
if ( OnLobbyDataUpdated != null ) { OnLobbyDataUpdated(); }
}
/// <summary>
/// Called when the lobby data itself has been updated. Called when someone has joined/left, Owner has updated data, etc.
/// </summary>
public Action OnLobbyDataUpdated;
/// <summary>
/// Called when a member of the lobby has updated either their personal Lobby metadata or someone's global steam state has changed (like a display name). Parameter is the user who changed.
/// </summary>
public Action<ulong> OnLobbyMemberDataUpdated;
public Type LobbyType
{
get
{
if ( !IsValid ) { return Type.Error; } //if we're currently in a valid server
//we know that we've set the lobby type via the lobbydata in the creation function
//ps this is important because steam doesn't have an easy way to get lobby type (why idk)
string lobbyType = CurrentLobbyData.GetData( "lobbytype" );
switch ( lobbyType )
{
case "Private":
return Type.Private;
case "FriendsOnly":
return Type.FriendsOnly;
case "Invisible":
return Type.Invisible;
case "Public":
return Type.Public;
default:
return Type.Error;
}
}
set
{
if ( !IsValid ) { return; }
if ( client.native.matchmaking.SetLobbyType( CurrentLobby, (SteamNative.LobbyType)value ) )
{
CurrentLobbyData.SetData( "lobbytype", value.ToString() );
}
}
}
private static byte[] chatMessageData = new byte[1024 * 4];
private unsafe void OnLobbyChatMessageRecievedAPI( LobbyChatMsg_t callback )
{
//from Client.Networking
if ( callback.SteamIDLobby != CurrentLobby )
return;
SteamNative.CSteamID steamid = 1;
ChatEntryType chatEntryType; // "If set then this will just always return k_EChatEntryTypeChatMsg. This can usually just be set to NULL."
int readData = 0;
fixed ( byte* p = chatMessageData )
{
readData = client.native.matchmaking.GetLobbyChatEntry( CurrentLobby, (int)callback.ChatID, out steamid, (IntPtr)p, chatMessageData.Length, out chatEntryType );
}
OnChatMessageRecieved?.Invoke( steamid, chatMessageData, readData );
if ( readData > 0 )
{
OnChatStringRecieved?.Invoke( steamid, Encoding.UTF8.GetString( chatMessageData, 0, readData ) );
}
}
/// <summary>
/// Callback to get chat messages. Use Encoding.UTF8.GetString to retrive the message.
/// </summary>
public Action<ulong, byte[], int> OnChatMessageRecieved;
/// <summary>
/// Like OnChatMessageRecieved but the data is converted to a string
/// </summary>
public Action<ulong, string> OnChatStringRecieved;
/// <summary>
/// Broadcasts a chat message to the all the users in the lobby users in the lobby (including the local user) will receive a LobbyChatMsg_t callback.
/// </summary>
/// <returns>True if message successfully sent</returns>
public unsafe bool SendChatMessage( string message )
{
var data = Encoding.UTF8.GetBytes( message );
fixed ( byte* p = data )
{
// pvMsgBody can be binary or text data, up to 4k
// if pvMsgBody is text, cubMsgBody should be strlen( text ) + 1, to include the null terminator
return client.native.matchmaking.SendLobbyChatMsg( CurrentLobby, (IntPtr)p, data.Length );
}
}
/// <summary>
/// Enums to catch the state of a user when their state has changed
/// </summary>
public enum MemberStateChange
{
Entered = ChatMemberStateChange.Entered,
Left = ChatMemberStateChange.Left,
Disconnected = ChatMemberStateChange.Disconnected,
Kicked = ChatMemberStateChange.Kicked,
Banned = ChatMemberStateChange.Banned,
}
internal void OnLobbyStateUpdatedAPI( LobbyChatUpdate_t callback )
{
if ( callback.SteamIDLobby != CurrentLobby )
return;
MemberStateChange change = (MemberStateChange)callback.GfChatMemberStateChange;
ulong initiator = callback.SteamIDMakingChange;
ulong affected = callback.SteamIDUserChanged;
OnLobbyStateChanged?.Invoke( change, initiator, affected );
}
/// <summary>
/// Called when the state of the Lobby is somehow shifted. Usually when someone joins or leaves the lobby.
/// The first ulong is the SteamID of the user that initiated the change.
/// The second ulong is the person that was affected
/// </summary>
public Action<MemberStateChange, ulong, ulong> OnLobbyStateChanged;
/// <summary>
/// The name of the lobby as a property for easy getting/setting. Note that this is setting LobbyData, which you cannot do unless you are the Owner of the lobby
/// </summary>
public string Name
{
get
{
if ( !IsValid ) { return ""; }
return CurrentLobbyData.GetData( "name" );
}
set
{
if ( !IsValid ) { return; }
CurrentLobbyData.SetData( "name", value );
}
}
/// <summary>
/// returns true if we're the current owner
/// </summary>
public bool IsOwner
{
get
{
return Owner == client.SteamId;
}
}
/// <summary>
/// The Owner of the current lobby. Returns 0 if you are not in a valid lobby.
/// </summary>
public ulong Owner
{
get
{
if ( IsValid )
{
return client.native.matchmaking.GetLobbyOwner( CurrentLobby );
}
return 0;
}
set
{
if ( Owner == value ) return;
client.native.matchmaking.SetLobbyOwner( CurrentLobby, value );
}
}
/// <summary>
/// Is the Lobby joinable by other people? Defaults to true;
/// </summary>
public bool Joinable
{
get
{
if ( !IsValid ) { return false; }
string joinable = CurrentLobbyData.GetData( "joinable" );
switch ( joinable )
{
case "true":
return true;
case "false":
return false;
default:
return false;
}
}
set
{
if ( !IsValid ) { return; }
if ( client.native.matchmaking.SetLobbyJoinable( CurrentLobby, value ) )
{
CurrentLobbyData.SetData( "joinable", value.ToString() );
}
}
}
/// <summary>
/// How many people can be in the Lobby
/// </summary>
public int MaxMembers
{
get
{
if ( !IsValid ) { return 0; } //0 is default, but value is inited when lobby is created.
return client.native.matchmaking.GetLobbyMemberLimit( CurrentLobby );
}
set
{
if ( !IsValid ) { return; }
client.native.matchmaking.SetLobbyMemberLimit( CurrentLobby, value );
}
}
/// <summary>
/// How many people are currently in the Lobby
/// </summary>
public int NumMembers
{
get { return client.native.matchmaking.GetNumLobbyMembers( CurrentLobby ); }
}
/// <summary>
/// Leave the CurrentLobby.
/// </summary>
public void Leave()
{
if ( CurrentLobby != 0 )
{
client.native.matchmaking.LeaveLobby( CurrentLobby );
}
CurrentLobby = 0;
CurrentLobbyData = null;
}
public void Dispose()
{
client = null;
}
/// <summary>
/// Get an array of all the CSteamIDs in the CurrentLobby.
/// Note that you must be in the Lobby you are trying to request the MemberIDs from.
/// Returns an empty array if you aren't in a lobby.
/// </summary>
/// <returns>Array of member SteamIDs</returns>
public ulong[] GetMemberIDs()
{
ulong[] memIDs = new ulong[NumMembers];
for ( int i = 0; i < NumMembers; i++ )
{
memIDs[i] = client.native.matchmaking.GetLobbyMemberByIndex( CurrentLobby, i );
}
return memIDs;
}
/// <summary>
/// Check to see if a user is in your CurrentLobby
/// </summary>
/// <param name="steamID">SteamID of the user to check for</param>
/// <returns></returns>
public bool UserIsInCurrentLobby( ulong steamID )
{
if ( CurrentLobby == 0 )
return false;
ulong[] mems = GetMemberIDs();
for ( int i = 0; i < mems.Length; i++ )
{
if ( mems[i] == steamID )
return true;
}
return false;
}
/// <summary>
/// Invites the specified user to the CurrentLobby the user is in.
/// </summary>
/// <param name="friendID">ulong ID of person to invite</param>
public bool InviteUserToLobby( ulong friendID )
{
return client.native.matchmaking.InviteUserToLobby( CurrentLobby, friendID );
}
internal void OnUserInvitedToLobbyAPI( LobbyInvite_t callback )
{
if ( callback.GameID != client.AppId ) return;
if ( OnUserInvitedToLobby != null ) { OnUserInvitedToLobby( callback.SteamIDLobby, callback.SteamIDUser ); }
}
/// <summary>
/// Activates the steam overlay to invite friends to the CurrentLobby the user is in.
/// </summary>
public void OpenFriendInviteOverlay()
{
client.native.friends.ActivateGameOverlayInviteDialog(CurrentLobby);
}
/// <summary>
/// Called when a user invites the current user to a lobby. The first parameter is the lobby the user was invited to, the second is the CSteamID of the person who invited this user
/// </summary>
public Action<ulong, ulong> OnUserInvitedToLobby;
/// <summary>
/// Called when a user accepts an invitation to a lobby while the game is running. The parameter is a lobby id.
/// </summary>
public Action<ulong> OnLobbyJoinRequested;
/// <summary>
/// Joins a lobby if a request was made to join the lobby through the friends list or an invite
/// </summary>
internal void OnLobbyJoinRequestedAPI( GameLobbyJoinRequested_t callback )
{
if (OnLobbyJoinRequested != null) { OnLobbyJoinRequested(callback.SteamIDLobby); }
}
/// <summary>
/// Makes sure we send an update callback if a Lobby user updates their information
/// </summary>
internal void OnLobbyMemberPersonaChangeAPI( PersonaStateChange_t callback )
{
if ( !UserIsInCurrentLobby( callback.SteamID ) ) return;
if ( OnLobbyMemberDataUpdated != null ) { OnLobbyMemberDataUpdated( callback.SteamID ); }
}
/// <summary>
/// Sets the game server associated with the lobby.
/// This can only be set by the owner of the lobby.
/// Either the IP/Port or the Steam ID of the game server must be valid, depending on how you want the clients to be able to connect.
/// </summary>
public bool SetGameServer( System.Net.IPAddress ip, int port, ulong serverSteamId = 0 )
{
if ( !IsValid || !IsOwner ) return false;
var ipint = System.Net.IPAddress.NetworkToHostOrder( ip.Address );
client.native.matchmaking.SetLobbyGameServer( CurrentLobby, (uint)ipint, (ushort)port, serverSteamId );
return true;
}
/// <summary>
/// Gets the details of a game server set in a lobby.
/// </summary>
public System.Net.IPAddress GameServerIp
{
get
{
uint ip;
ushort port;
CSteamID steamid;
if ( !client.native.matchmaking.GetLobbyGameServer( CurrentLobby, out ip, out port, out steamid ) || ip == 0 )
return null;
return new System.Net.IPAddress( System.Net.IPAddress.HostToNetworkOrder( ip ) );
}
}
/// <summary>
/// Gets the details of a game server set in a lobby.
/// </summary>
public int GameServerPort
{
get
{
uint ip;
ushort port;
CSteamID steamid;
if ( !client.native.matchmaking.GetLobbyGameServer( CurrentLobby, out ip, out port, out steamid ) )
return 0;
return (int)port;
}
}
/// <summary>
/// Gets the details of a game server set in a lobby.
/// </summary>
public ulong GameServerSteamId
{
get
{
uint ip;
ushort port;
CSteamID steamid;
if ( !client.native.matchmaking.GetLobbyGameServer( CurrentLobby, out ip, out port, out steamid ) )
return 0;
return steamid;
}
}
/*not implemented
//set the game server of the lobby
client.native.matchmaking.GetLobbyGameServer;
client.native.matchmaking.SetLobbyGameServer;
//used with game server stuff
SteamNative.LobbyGameCreated_t
*/
}
}

View File

@ -1,77 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Facepunch.Steamworks
{
public partial class LobbyList
{
public class Lobby
{
private Dictionary<string, string> lobbyData;
internal Client Client;
public string Name { get; private set; }
public ulong LobbyID { get; private set; }
public ulong Owner { get; private set; }
public int MemberLimit{ get; private set; }
public int NumMembers{ get; private set; }
public string LobbyType { get; private set; }
/// <summary>
/// Get the lobby value for the specific key
/// </summary>
/// <param name="k">The key to find</param>
/// <returns>The value at key</returns>
public string GetData(string k)
{
if (lobbyData.TryGetValue(k, out var v))
return v;
return string.Empty;
}
/// <summary>
/// Get a list of all the data in the Lobby
/// </summary>
/// <returns>Dictionary of all the key/value pairs in the data</returns>
public Dictionary<string, string> GetAllData()
{
var returnData = new Dictionary<string, string>();
foreach ( var item in lobbyData)
{
returnData.Add(item.Key, item.Value);
}
return returnData;
}
internal static Lobby FromSteam(Client client, ulong lobby)
{
var lobbyData = new Dictionary<string, string>();
int dataCount = client.native.matchmaking.GetLobbyDataCount(lobby);
for (int i = 0; i < dataCount; i++)
{
if (client.native.matchmaking.GetLobbyDataByIndex(lobby, i, out var datakey, out var datavalue))
{
lobbyData.Add(datakey, datavalue);
}
}
return new Lobby()
{
Client = client,
LobbyID = lobby,
Name = client.native.matchmaking.GetLobbyData(lobby, "name"),
LobbyType = client.native.matchmaking.GetLobbyData(lobby, "lobbytype"),
MemberLimit = client.native.matchmaking.GetLobbyMemberLimit(lobby),
Owner = client.native.matchmaking.GetLobbyOwner(lobby),
NumMembers = client.native.matchmaking.GetNumLobbyMembers(lobby),
lobbyData = lobbyData
};
}
}
}
}

View File

@ -1,185 +0,0 @@
using System;
using System.Collections.Generic;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public partial class LobbyList : IDisposable
{
internal Client client;
//The list of retrieved lobbies
public List<Lobby> Lobbies { get; private set; }
//True when all the possible lobbies have had their data updated
//if the number of lobbies is now equal to the initial request number, we've found all lobbies
public bool Finished { get; private set; }
//The number of possible lobbies we can get data from
internal List<ulong> requests;
internal LobbyList(Client client)
{
this.client = client;
Lobbies = new List<Lobby>();
requests = new List<ulong>();
}
/// <summary>
/// Refresh the List of Lobbies. If no filter is passed in, a default one is created that filters based on AppId ("appid").
/// </summary>
/// <param name="filter"></param>
public void Refresh ( Filter filter = null)
{
//init out values
Lobbies.Clear();
requests.Clear();
Finished = false;
if (filter == null)
{
filter = new Filter();
filter.StringFilters.Add("appid", client.AppId.ToString());
client.native.matchmaking.RequestLobbyList(OnLobbyList);
return;
}
client.native.matchmaking.AddRequestLobbyListDistanceFilter((SteamNative.LobbyDistanceFilter)filter.DistanceFilter);
if (filter.SlotsAvailable != null)
{
client.native.matchmaking.AddRequestLobbyListFilterSlotsAvailable((int)filter.SlotsAvailable);
}
if (filter.MaxResults != null)
{
client.native.matchmaking.AddRequestLobbyListResultCountFilter((int)filter.MaxResults);
}
foreach (KeyValuePair<string, string> fil in filter.StringFilters)
{
client.native.matchmaking.AddRequestLobbyListStringFilter(fil.Key, fil.Value, SteamNative.LobbyComparison.Equal);
}
foreach (KeyValuePair<string, int> fil in filter.NearFilters)
{
client.native.matchmaking.AddRequestLobbyListNearValueFilter(fil.Key, fil.Value);
}
//foreach (KeyValuePair<string, KeyValuePair<Filter.Comparison, int>> fil in filter.NumericalFilters)
//{
// client.native.matchmaking.AddRequestLobbyListNumericalFilter(fil.Key, fil.Value.Value, (SteamNative.LobbyComparison)fil.Value.Key);
//}
// this will never return lobbies that are full (via the actual api)
client.native.matchmaking.RequestLobbyList(OnLobbyList);
}
void OnLobbyList(LobbyMatchList_t callback, bool error)
{
if (error) return;
//how many lobbies matched
uint lobbiesMatching = callback.LobbiesMatching;
// lobbies are returned in order of closeness to the user, so add them to the list in that order
for (int i = 0; i < lobbiesMatching; i++)
{
//add the lobby to the list of requests
ulong lobby = client.native.matchmaking.GetLobbyByIndex(i);
requests.Add(lobby);
//cast to a LobbyList.Lobby
Lobby newLobby = Lobby.FromSteam(client, lobby);
if (newLobby.Name != "")
{
//if the lobby is valid add it to the valid return lobbies
Lobbies.Add(newLobby);
checkFinished();
}
else
{
//else we need to get the info for the missing lobby
client.native.matchmaking.RequestLobbyData(lobby);
client.RegisterCallback<SteamNative.LobbyDataUpdate_t>( OnLobbyDataUpdated );
}
}
checkFinished();
if (OnLobbiesUpdated != null) { OnLobbiesUpdated(); }
}
void checkFinished()
{
if (Lobbies.Count == requests.Count)
{
Finished = true;
return;
}
Finished = false;
}
void OnLobbyDataUpdated(LobbyDataUpdate_t callback)
{
if (callback.Success == 1) //1 if success, 0 if failure
{
//find the lobby that has been updated
Lobby lobby = Lobbies.Find(x => x.LobbyID == callback.SteamIDLobby);
//if this lobby isn't yet in the list of lobbies, we know that we should add it
if (lobby == null)
{
Lobbies.Add(lobby);
checkFinished();
}
//otherwise lobby data in general was updated and you should listen to see what changed
if (OnLobbiesUpdated != null) { OnLobbiesUpdated(); }
}
}
public Action OnLobbiesUpdated;
public void Dispose()
{
client = null;
}
public class Filter
{
// Filters that match actual metadata keys exactly
public Dictionary<string, string> StringFilters = new Dictionary<string, string>();
// Filters that are of string key and int value for that key to be close to
public Dictionary<string, int> NearFilters = new Dictionary<string, int>();
//Filters that are of string key and int value, with a comparison filter to say how we should relate to the value
//public Dictionary<string, KeyValuePair<Comparison, int>> NumericalFilters = new Dictionary<string, KeyValuePair<Comparison, int>>();
public Distance DistanceFilter = Distance.Worldwide;
public int? SlotsAvailable { get; set; }
public int? MaxResults { get; set; }
public enum Distance : int
{
Close = SteamNative.LobbyDistanceFilter.Close,
Default = SteamNative.LobbyDistanceFilter.Default,
Far = SteamNative.LobbyDistanceFilter.Far,
Worldwide = SteamNative.LobbyDistanceFilter.Worldwide
}
public enum Comparison : int
{
EqualToOrLessThan = SteamNative.LobbyComparison.EqualToOrLessThan,
LessThan = SteamNative.LobbyComparison.LessThan,
Equal = SteamNative.LobbyComparison.Equal,
GreaterThan = SteamNative.LobbyComparison.GreaterThan,
EqualToOrGreaterThan = SteamNative.LobbyComparison.EqualToOrGreaterThan,
NotEqual = SteamNative.LobbyComparison.NotEqual
}
}
}
}

View File

@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public class MicroTransactions : IDisposable
{
internal Client client;
public delegate void AuthorizationResponse( bool authorized, int appId, ulong orderId );
/// <summary>
/// Called on the MicroTxnAuthorizationResponse_t event
/// </summary>
public event AuthorizationResponse OnAuthorizationResponse;
internal MicroTransactions( Client c )
{
client = c;
client.RegisterCallback<SteamNative.MicroTxnAuthorizationResponse_t>( onMicroTxnAuthorizationResponse );
}
private void onMicroTxnAuthorizationResponse( MicroTxnAuthorizationResponse_t arg1 )
{
if ( OnAuthorizationResponse != null )
{
OnAuthorizationResponse( arg1.Authorized == 1, (int) arg1.AppID, arg1.OrderID );
}
}
public void Dispose()
{
client = null;
}
}
}

View File

@ -1,54 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public partial class Client : IDisposable
{
private Overlay _overlay;
public Overlay Overlay
{
get
{
if ( _overlay == null )
_overlay = new Overlay { client = this };
return _overlay;
}
}
}
public class Overlay
{
internal Client client;
/// <summary>
/// Returns true if the Steam Overlay is actually available, false if it was not injected properly.
/// Note that it may take some time after Steam_Init() until the overlay injection is complete.
/// Also note that the overlay will only work if the Steam API is initialized before the rendering device is initialized. That means that
/// for Unity3D games the overlay is only available if the game was launched directly through Steam. Calling Steam_Init() from Mono
/// code is too late.
/// </summary>
public bool Enabled
{
get { return client.native != null ? client.native.utils.IsOverlayEnabled() : false; }
}
public void OpenUserPage( string name, ulong steamid ) { client.native.friends.ActivateGameOverlayToUser( name, steamid ); }
public void OpenProfile( ulong steamid ) { OpenUserPage( "steamid", steamid ); }
public void OpenChat( ulong steamid ){ OpenUserPage( "chat", steamid ); }
public void OpenTrade( ulong steamid ) { OpenUserPage( "jointrade", steamid ); }
public void OpenStats( ulong steamid ) { OpenUserPage( "stats", steamid ); }
public void OpenAchievements( ulong steamid ) { OpenUserPage( "achievements", steamid ); }
public void AddFriend( ulong steamid ) { OpenUserPage( "friendadd", steamid ); }
public void RemoveFriend( ulong steamid ) { OpenUserPage( "friendremove", steamid ); }
public void AcceptFriendRequest( ulong steamid ) { OpenUserPage( "friendrequestaccept", steamid ); }
public void IgnoreFriendRequest( ulong steamid ) { OpenUserPage( "friendrequestignore", steamid ); }
public void OpenUrl( string url ) { client.native.friends.ActivateGameOverlayToWebPage( url ); }
}
}

View File

@ -1,306 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Facepunch.Steamworks.Callbacks;
using SteamNative;
using Result = SteamNative.Result;
namespace Facepunch.Steamworks
{
/// <summary>
/// Represents a file stored in a user's Steam Cloud.
/// </summary>
public class RemoteFile
{
internal readonly RemoteStorage remoteStorage;
private readonly bool _isUgc;
private string _fileName;
private int _sizeInBytes = -1;
private UGCHandle_t _handle;
private ulong _ownerId;
private bool _isDownloading;
private byte[] _downloadedData;
/// <summary>
/// Check if the file exists.
/// </summary>
public bool Exists { get; internal set; }
public bool IsDownloading { get { return _isUgc && _isDownloading && _downloadedData == null; } }
public bool IsDownloaded { get { return !_isUgc || _downloadedData != null; } }
/// <summary>
/// If true, the file is available for other users to download.
/// </summary>
public bool IsShared { get { return _handle.Value != 0; } }
internal UGCHandle_t UGCHandle { get { return _handle; } }
public ulong SharingId { get { return UGCHandle.Value; } }
/// <summary>
/// Name and path of the file.
/// </summary>
public string FileName
{
get
{
if ( _fileName != null ) return _fileName;
GetUGCDetails();
return _fileName;
}
}
/// <summary>
/// Steam ID of the file's owner.
/// </summary>
public ulong OwnerId
{
get
{
if ( _ownerId != 0 ) return _ownerId;
GetUGCDetails();
return _ownerId;
}
}
/// <summary>
/// Total size of the file in bytes.
/// </summary>
public int SizeInBytes
{
get
{
if ( _sizeInBytes != -1 ) return _sizeInBytes;
if ( _isUgc ) throw new NotImplementedException();
_sizeInBytes = remoteStorage.native.GetFileSize( FileName );
return _sizeInBytes;
}
internal set { _sizeInBytes = value; }
}
internal RemoteFile( RemoteStorage r, UGCHandle_t handle )
{
Exists = true;
remoteStorage = r;
_isUgc = true;
_handle = handle;
}
internal RemoteFile( RemoteStorage r, string name, ulong ownerId, int sizeInBytes = -1 )
{
remoteStorage = r;
_isUgc = false;
_fileName = name;
_ownerId = ownerId;
_sizeInBytes = sizeInBytes;
}
/// <summary>
/// Creates a <see cref="RemoteFileWriteStream"/> used to write to this file.
/// </summary>
public RemoteFileWriteStream OpenWrite()
{
if (_isUgc) throw new InvalidOperationException("Cannot write to a shared file.");
return new RemoteFileWriteStream( remoteStorage, this );
}
/// <summary>
/// Write a byte array to this file, replacing any existing contents.
/// </summary>
public void WriteAllBytes( byte[] buffer )
{
using ( var stream = OpenWrite() )
{
stream.Write( buffer, 0, buffer.Length );
}
}
/// <summary>
/// Write a string to this file, replacing any existing contents.
/// </summary>
public void WriteAllText( string text, Encoding encoding = null )
{
if ( encoding == null ) encoding = Encoding.UTF8;
WriteAllBytes( encoding.GetBytes( text ) );
}
/// <summary>
/// Callback invoked by <see cref="RemoteFile.Download"/> when a file download is complete.
/// </summary>
public delegate void DownloadCallback();
/// <summary>
/// Gets the number of bytes downloaded and the total number of bytes expected while
/// this file is downloading.
/// </summary>
/// <returns>True if the file is downloading</returns>
public bool GetDownloadProgress( out int bytesDownloaded, out int bytesExpected )
{
return remoteStorage.native.GetUGCDownloadProgress( _handle, out bytesDownloaded, out bytesExpected );
}
/// <summary>
/// Attempts to start downloading a shared file.
/// </summary>
/// <returns>True if the download has successfully started</returns>
public bool Download( DownloadCallback onSuccess = null, FailureCallback onFailure = null )
{
if ( !_isUgc ) return false;
if ( _isDownloading ) return false;
if ( IsDownloaded ) return false;
_isDownloading = true;
remoteStorage.native.UGCDownload( _handle, 1000, ( result, error ) =>
{
_isDownloading = false;
if ( error || result.Result != Result.OK )
{
onFailure?.Invoke( result.Result == 0 ? Callbacks.Result.IOFailure : (Callbacks.Result) result.Result );
return;
}
_ownerId = result.SteamIDOwner;
_sizeInBytes = result.SizeInBytes;
_fileName = result.PchFileName;
unsafe
{
_downloadedData = new byte[_sizeInBytes];
fixed ( byte* bufferPtr = _downloadedData )
{
remoteStorage.native.UGCRead( _handle, (IntPtr) bufferPtr, _sizeInBytes, 0, UGCReadAction.ontinueReading );
}
}
onSuccess?.Invoke();
} );
return true;
}
/// <summary>
/// Opens a stream used to read from this file.
/// </summary>
/// <returns></returns>
public Stream OpenRead()
{
return new MemoryStream( ReadAllBytes(), false );
}
/// <summary>
/// Reads the entire contents of the file as a byte array.
/// </summary>
public unsafe byte[] ReadAllBytes()
{
if ( _isUgc )
{
if ( !IsDownloaded ) throw new Exception( "Cannot read a file that hasn't been downloaded." );
return _downloadedData;
}
var size = SizeInBytes;
var buffer = new byte[size];
fixed ( byte* bufferPtr = buffer )
{
remoteStorage.native.FileRead( FileName, (IntPtr) bufferPtr, size );
}
return buffer;
}
/// <summary>
/// Reads the entire contents of the file as a string.
/// </summary>
public string ReadAllText( Encoding encoding = null )
{
if ( encoding == null ) encoding = Encoding.UTF8;
return encoding.GetString( ReadAllBytes() );
}
/// <summary>
/// Callback invoked by <see cref="RemoteFile.Share"/> when file sharing is complete.
/// </summary>
public delegate void ShareCallback();
/// <summary>
/// Attempt to publish this file for other users to download.
/// </summary>
/// <returns>True if we have started attempting to share</returns>
public bool Share( ShareCallback onSuccess = null, FailureCallback onFailure = null )
{
if ( _isUgc ) return false;
// Already shared
if ( _handle.Value != 0 ) return false;
remoteStorage.native.FileShare( FileName, ( result, error ) =>
{
if ( !error && result.Result == Result.OK )
{
_handle.Value = result.File;
onSuccess?.Invoke();
}
else
{
onFailure?.Invoke( result.Result == 0 ? Callbacks.Result.IOFailure : (Callbacks.Result) result.Result );
}
} );
return true;
}
/// <summary>
/// Delete this file from remote storage.
/// </summary>
/// <returns>True if the file could be deleted</returns>
public bool Delete()
{
if ( !Exists ) return false;
if ( _isUgc ) return false;
if ( !remoteStorage.native.FileDelete( FileName ) ) return false;
Exists = false;
remoteStorage.InvalidateFiles();
return true;
}
/// <summary>
/// Remove this file from remote storage, while keeping a local copy.
/// Writing to this file again will re-add it to the cloud.
/// </summary>
/// <returns>True if the file was forgotten</returns>
public bool Forget()
{
if ( !Exists ) return false;
if ( _isUgc ) return false;
return remoteStorage.native.FileForget( FileName );
}
private void GetUGCDetails()
{
if ( !_isUgc ) throw new InvalidOperationException();
var appId = new AppId_t { Value = remoteStorage.native.steamworks.AppId };
CSteamID ownerId;
remoteStorage.native.GetUGCDetails( _handle, ref appId, out _fileName, out ownerId );
_ownerId = ownerId.Value;
}
}
}

View File

@ -1,94 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
/// <summary>
/// Stream used to write to a <see cref="RemoteFile"/>.
/// </summary>
public class RemoteFileWriteStream : Stream
{
internal readonly RemoteStorage remoteStorage;
private readonly UGCFileWriteStreamHandle_t _handle;
private readonly RemoteFile _file;
private int _written;
private bool _closed;
internal RemoteFileWriteStream( RemoteStorage r, RemoteFile file )
{
remoteStorage = r;
_handle = remoteStorage.native.FileWriteStreamOpen( file.FileName );
_file = file;
}
public override void Flush() { }
public override int Read( byte[] buffer, int offset, int count )
{
throw new NotImplementedException();
}
public override long Seek( long offset, SeekOrigin origin )
{
throw new NotImplementedException();
}
public override void SetLength( long value )
{
throw new NotImplementedException();
}
public override unsafe void Write( byte[] buffer, int offset, int count )
{
if ( _closed ) throw new ObjectDisposedException( ToString() );
fixed ( byte* bufferPtr = buffer )
{
if ( remoteStorage.native.FileWriteStreamWriteChunk( _handle, (IntPtr)(bufferPtr + offset), count ) )
{
_written += count;
}
}
}
public override bool CanRead => false;
public override bool CanSeek => false;
public override bool CanWrite => true;
public override long Length => _written;
public override long Position { get { return _written; } set { throw new NotImplementedException(); } }
/// <summary>
/// Close the stream without saving the file to remote storage.
/// </summary>
public void Cancel()
{
if ( _closed ) return;
_closed = true;
remoteStorage.native.FileWriteStreamCancel( _handle );
}
public override void Close()
{
if ( _closed ) return;
_closed = true;
remoteStorage.native.FileWriteStreamClose( _handle );
_file.remoteStorage.OnWrittenNewFile( _file );
}
protected override void Dispose( bool disposing )
{
if ( disposing ) Close();
base.Dispose( disposing );
}
}
}

View File

@ -1,267 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
/// <summary>
/// Handles Steam Cloud related actions.
/// </summary>
public class RemoteStorage : IDisposable
{
private static string NormalizePath( string path )
{
// TODO: DUMB HACK ALERT
return SteamNative.Platform.IsWindows
? new FileInfo( $"x:/{path}" ).FullName.Substring( 3 )
: new FileInfo( $"/x/{path}" ).FullName.Substring( 3 );
}
internal Client client;
internal SteamNative.SteamRemoteStorage native;
private bool _filesInvalid = true;
private readonly List<RemoteFile> _files = new List<RemoteFile>();
internal RemoteStorage( Client c )
{
client = c;
native = client.native.remoteStorage;
}
/// <summary>
/// True if Steam Cloud is currently enabled by the current user.
/// </summary>
public bool IsCloudEnabledForAccount
{
get { return native.IsCloudEnabledForAccount(); }
}
/// <summary>
/// True if Steam Cloud is currently enabled for this app by the current user.
/// </summary>
public bool IsCloudEnabledForApp
{
get { return native.IsCloudEnabledForApp(); }
}
/// <summary>
/// Gets the total number of files in the current user's remote storage for the current game.
/// </summary>
public int FileCount
{
get { return native.GetFileCount(); }
}
/// <summary>
/// Gets all files in the current user's remote storage for the current game.
/// </summary>
public IEnumerable<RemoteFile> Files
{
get
{
UpdateFiles();
return _files;
}
}
/// <summary>
/// Creates a new <see cref="RemoteFile"/> with the given <paramref name="path"/>.
/// If a file exists at that path it will be overwritten.
/// </summary>
public RemoteFile CreateFile( string path )
{
path = NormalizePath( path );
InvalidateFiles();
var existing = Files.FirstOrDefault( x => x.FileName == path );
return existing ?? new RemoteFile( this, path, client.SteamId, 0 );
}
/// <summary>
/// Opens the file if it exists, else returns null;
/// </summary>
public RemoteFile OpenFile( string path )
{
path = NormalizePath( path );
InvalidateFiles();
var existing = Files.FirstOrDefault( x => x.FileName == path );
return existing;
}
/// <summary>
/// Opens a previously shared <see cref="RemoteFile"/>
/// with the given <paramref name="sharingId"/>.
/// </summary>
public RemoteFile OpenSharedFile( ulong sharingId )
{
return new RemoteFile( this, sharingId );
}
/// <summary>
/// Write all text to the file at the specified path. This
/// overwrites the contents - it does not append.
/// </summary>
public bool WriteString( string path, string text, Encoding encoding = null )
{
var file = CreateFile( path );
file.WriteAllText( text, encoding );
return file.Exists;
}
/// <summary>
/// Write all data to the file at the specified path. This
/// overwrites the contents - it does not append.
/// </summary>
public bool WriteBytes( string path, byte[] data )
{
var file = CreateFile( path );
file.WriteAllBytes( data );
return file.Exists;
}
/// <summary>
/// Read the entire contents of the file as a string.
/// Returns null if the file isn't found.
/// </summary>
public string ReadString( string path, Encoding encoding = null )
{
var file = OpenFile( path );
if ( file == null ) return null;
return file.ReadAllText( encoding );
}
/// <summary>
/// Read the entire contents of the file as raw data.
/// Returns null if the file isn't found.
/// </summary>
public byte[] ReadBytes( string path )
{
var file = OpenFile( path );
if ( file == null ) return null;
return file.ReadAllBytes();
}
internal void OnWrittenNewFile( RemoteFile file )
{
if ( _files.Any( x => x.FileName == file.FileName ) ) return;
_files.Add( file );
file.Exists = true;
InvalidateFiles();
}
internal void InvalidateFiles()
{
_filesInvalid = true;
}
private void UpdateFiles()
{
if ( !_filesInvalid ) return;
_filesInvalid = false;
foreach ( var file in _files )
{
file.Exists = false;
}
var count = FileCount;
for ( var i = 0; i < count; ++i )
{
int size;
var name = NormalizePath( native.GetFileNameAndSize( i, out size ) );
var existing = _files.FirstOrDefault( x => x.FileName == name );
if ( existing == null )
{
existing = new RemoteFile( this, name, client.SteamId, size );
_files.Add( existing );
}
else
{
existing.SizeInBytes = size;
}
existing.Exists = true;
}
for ( var i = _files.Count - 1; i >= 0; --i )
{
if ( !_files[i].Exists ) _files.RemoveAt( i );
}
}
/// <summary>
/// Gets whether a file exists in remote storage at the given <paramref name="path"/>.
/// </summary>
public bool FileExists( string path )
{
return native.FileExists( path );
}
public void Dispose()
{
client = null;
native = null;
}
/// <summary>
/// Number of bytes used out of the user's total quota
/// </summary>
public ulong QuotaUsed
{
get
{
ulong totalBytes = 0;
ulong availableBytes = 0;
if ( !native.GetQuota( out totalBytes, out availableBytes ) )
return 0;
return totalBytes - availableBytes;
}
}
/// <summary>
/// Total quota size in bytes
/// </summary>
public ulong QuotaTotal
{
get
{
ulong totalBytes = 0;
ulong availableBytes = 0;
if ( !native.GetQuota( out totalBytes, out availableBytes ) )
return 0;
return totalBytes;
}
}
/// <summary>
/// Number of bytes remaining out of the user's total quota
/// </summary>
public ulong QuotaRemaining
{
get
{
ulong totalBytes = 0;
ulong availableBytes = 0;
if ( !native.GetQuota( out totalBytes, out availableBytes ) )
return 0;
return availableBytes;
}
}
}
}

View File

@ -1,80 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public partial class Client : IDisposable
{
Screenshots _screenshots;
public Screenshots Screenshots
{
get
{
if ( _screenshots == null )
_screenshots = new Screenshots( this );
return _screenshots;
}
}
}
public class Screenshots
{
internal Client client;
internal Screenshots( Client c )
{
client = c;
}
public void Trigger()
{
client.native.screenshots.TriggerScreenshot();
}
public unsafe void Write( byte[] rgbData, int width, int height )
{
if ( rgbData == null )
{
throw new ArgumentNullException( nameof(rgbData) );
}
if ( width < 1 )
{
throw new ArgumentOutOfRangeException( nameof(width), width,
$"Expected {nameof(width)} to be at least 1." );
}
if ( height < 1 )
{
throw new ArgumentOutOfRangeException( nameof(height), height,
$"Expected {nameof(height)} to be at least 1." );
}
var size = width * height * 3;
if ( rgbData.Length < size )
{
throw new ArgumentException( nameof(rgbData),
$"Expected {nameof(rgbData)} to contain at least {size} elements (actual size: {rgbData.Length})." );
}
fixed ( byte* ptr = rgbData )
{
client.native.screenshots.WriteScreenshot( (IntPtr) ptr, (uint) rgbData.Length, width, height );
}
}
public unsafe void AddScreenshotToLibrary( string filename, string thumbnailFilename, int width, int height)
{
client.native.screenshots.AddScreenshotToLibrary(filename, thumbnailFilename, width, height);
}
public unsafe void AddScreenshotToLibrary( string filename, int width, int height)
{
client.native.screenshots.AddScreenshotToLibrary(filename, null, width, height);
}
}
}

View File

@ -1,232 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Facepunch.Steamworks
{
public partial class ServerList
{
public class Request : IDisposable
{
internal Client client;
internal List<SubRequest> Requests = new List<SubRequest>();
internal class SubRequest
{
internal IntPtr Request;
internal int Pointer = 0;
internal List<int> WatchList = new List<int>();
internal System.Diagnostics.Stopwatch Timer = System.Diagnostics.Stopwatch.StartNew();
internal bool Update( SteamNative.SteamMatchmakingServers servers, Action<SteamNative.gameserveritem_t> OnServer, Action OnUpdate )
{
if ( Request == IntPtr.Zero )
return true;
if ( Timer.Elapsed.TotalSeconds < 0.5f )
return false;
Timer.Reset();
Timer.Start();
bool changes = false;
//
// Add any servers we're not watching to our watch list
//
var count = servers.GetServerCount( Request );
if ( count != Pointer )
{
for ( int i = Pointer; i < count; i++ )
{
WatchList.Add( i );
}
}
Pointer = count;
//
// Remove any servers that respond successfully
//
WatchList.RemoveAll( x =>
{
var info = servers.GetServerDetails( Request, x );
if ( info.HadSuccessfulResponse )
{
OnServer( info );
changes = true;
return true;
}
return false;
} );
//
// If we've finished refreshing
//
if ( servers.IsRefreshing( Request ) == false )
{
//
// Put any other servers on the 'no response' list
//
WatchList.RemoveAll( x =>
{
var info = servers.GetServerDetails( Request, x );
OnServer( info );
return true;
} );
servers.CancelQuery( Request );
Request = IntPtr.Zero;
changes = true;
}
if ( changes && OnUpdate != null )
OnUpdate();
return Request == IntPtr.Zero;
}
}
public Action OnUpdate;
public Action<Server> OnServerResponded;
public Action OnFinished;
/// <summary>
/// A list of servers that responded. If you're only interested in servers that responded since you
/// last updated, then simply clear this list.
/// </summary>
public List<Server> Responded = new List<Server>();
/// <summary>
/// A list of servers that were in the master list but didn't respond.
/// </summary>
public List<Server> Unresponsive = new List<Server>();
/// <summary>
/// True when we have finished
/// </summary>
public bool Finished = false;
internal Request( Client c )
{
client = c;
client.OnUpdate += Update;
}
~Request()
{
Dispose();
}
internal IEnumerable<string> ServerList { get; set; }
internal Filter Filter { get; set; }
internal void StartCustomQuery()
{
if ( ServerList == null )
return;
int blockSize = 16;
int Pointer = 0;
while ( true )
{
var sublist = ServerList.Skip( Pointer ).Take( blockSize );
if ( sublist.Count() == 0 )
break;
Pointer += sublist.Count();
var filter = new Filter();
filter.Add( "or", sublist.Count().ToString() );
foreach ( var server in sublist )
{
filter.Add( "gameaddr", server );
}
filter.Start();
var id = client.native.servers.RequestInternetServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero );
filter.Free();
AddRequest( id );
}
ServerList = null;
}
internal void AddRequest( IntPtr id )
{
Requests.Add( new SubRequest() { Request = id } );
}
private void Update()
{
if ( Requests.Count == 0 )
return;
for( int i=0; i< Requests.Count(); i++ )
{
if ( Requests[i].Update( client.native.servers, OnServer, OnUpdate ) )
{
Requests.RemoveAt( i );
i--;
}
}
if ( Requests.Count == 0 )
{
Finished = true;
client.OnUpdate -= Update;
OnFinished?.Invoke();
}
}
private void OnServer( SteamNative.gameserveritem_t info )
{
if ( info.HadSuccessfulResponse )
{
if ( Filter != null && !Filter.Test( info ) )
return;
var s = Server.FromSteam( client, info );
Responded.Add( s );
OnServerResponded?.Invoke( s );
}
else
{
Unresponsive.Add( Server.FromSteam( client, info ) );
}
}
/// <summary>
/// Disposing will end the query
/// </summary>
public void Dispose()
{
if ( client.IsValid )
client.OnUpdate -= Update;
//
// Cancel the query if it's still running
//
foreach( var subRequest in Requests )
{
if ( client.IsValid )
client.native.servers.CancelQuery( subRequest.Request );
}
Requests.Clear();
}
}
}
}

View File

@ -1,160 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
namespace Facepunch.Steamworks
{
public partial class ServerList
{
public class Server
{
public string Name { get; set; }
public int Ping { get; set; }
public string GameDir { get; set; }
public string Map { get; set; }
public string Description { get; set; }
public uint AppId { get; set; }
public int Players { get; set; }
public int MaxPlayers { get; set; }
public int BotPlayers { get; set; }
public bool Passworded { get; set; }
public bool Secure { get; set; }
public uint LastTimePlayed { get; set; }
public int Version { get; set; }
public string[] Tags { get; set; }
public ulong SteamId { get; set; }
public IPAddress Address { get; set; }
public int ConnectionPort { get; set; }
public int QueryPort { get; set; }
/// <summary>
/// Returns true if this server is in the favourites list
/// </summary>
public bool Favourite
{
get
{
return Client.ServerList.IsFavourite( this );
}
}
internal Client Client;
internal static Server FromSteam( Client client, SteamNative.gameserveritem_t item )
{
return new Server()
{
Client = client,
Address = Utility.Int32ToIp( item.NetAdr.IP ),
ConnectionPort = item.NetAdr.ConnectionPort,
QueryPort = item.NetAdr.QueryPort,
Name = item.ServerName,
Ping = item.Ping,
GameDir = item.GameDir,
Map = item.Map,
Description = item.GameDescription,
AppId = item.AppID,
Players = item.Players,
MaxPlayers = item.MaxPlayers,
BotPlayers = item.BotPlayers,
Passworded = item.Password,
Secure = item.Secure,
LastTimePlayed = item.TimeLastPlayed,
Version = item.ServerVersion,
Tags = item.GameTags == null ? null : item.GameTags.Split( ',' ),
SteamId = item.SteamID
};
}
/// <summary>
/// Callback when rules are receieved.
/// The bool is true if server responded properly.
/// </summary>
public Action<bool> OnReceivedRules;
/// <summary>
/// List of server rules. Use HasRules to see if this is safe to access.
/// </summary>
public Dictionary<string, string> Rules;
/// <summary>
/// Returns true if this server has rules
/// </summary>
public bool HasRules { get { return Rules != null && Rules.Count > 0; } }
internal SourceServerQuery RulesRequest;
/// <summary>
/// Populates Rules for this server
/// </summary>
public void FetchRules()
{
if ( RulesRequest != null )
return;
Rules = null;
RulesRequest = new SourceServerQuery( this, Address, QueryPort );
}
internal void OnServerRulesReceiveFinished( Dictionary<string, string> rules, bool Success )
{
RulesRequest = null;
if ( Success )
{
Rules = rules;
}
if ( OnReceivedRules != null )
{
OnReceivedRules( Success );
}
}
internal const uint k_unFavoriteFlagNone = 0x00;
internal const uint k_unFavoriteFlagFavorite = 0x01; // this game favorite entry is for the favorites list
internal const uint k_unFavoriteFlagHistory = 0x02; // this game favorite entry is for the history list
/// <summary>
/// Add this server to our history list
/// If we're already in the history list, weill set the last played time to now
/// </summary>
public void AddToHistory()
{
Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory, (uint)Utility.Epoch.Current );
Client.ServerList.UpdateFavouriteList();
}
/// <summary>
/// Remove this server from our history list
/// </summary>
public void RemoveFromHistory()
{
Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagHistory );
Client.ServerList.UpdateFavouriteList();
}
/// <summary>
/// Add this server to our favourite list
/// </summary>
public void AddToFavourites()
{
Client.native.matchmaking.AddFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite, (uint)Utility.Epoch.Current );
Client.ServerList.UpdateFavouriteList();
}
/// <summary>
/// Remove this server from our favourite list
/// </summary>
public void RemoveFromFavourites()
{
Client.native.matchmaking.RemoveFavoriteGame( AppId, Utility.IpToInt32( Address ), (ushort)ConnectionPort, (ushort)QueryPort, k_unFavoriteFlagFavorite );
Client.ServerList.UpdateFavouriteList();
}
}
}
}

View File

@ -1,267 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public partial class ServerList : IDisposable
{
internal Client client;
internal ServerList( Client client )
{
this.client = client;
UpdateFavouriteList();
}
HashSet<ulong> FavouriteHash = new HashSet<ulong>();
HashSet<ulong> HistoryHash = new HashSet<ulong>();
internal void UpdateFavouriteList()
{
FavouriteHash.Clear();
HistoryHash.Clear();
for ( int i=0; i< client.native.matchmaking.GetFavoriteGameCount(); i++ )
{
AppId_t appid = 0;
uint ip;
ushort conPort;
ushort queryPort;
uint lastplayed;
uint flags;
client.native.matchmaking.GetFavoriteGame( i, ref appid, out ip, out conPort, out queryPort, out flags, out lastplayed );
ulong encoded = ip;
encoded = encoded << 32;
encoded = encoded | (uint)conPort;
if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite )
FavouriteHash.Add( encoded );
if ( ( flags & Server.k_unFavoriteFlagFavorite ) == Server.k_unFavoriteFlagFavorite )
HistoryHash.Add( encoded );
}
}
public void Dispose()
{
client = null;
}
public class Filter : List<KeyValuePair<string, string>>
{
public void Add( string k, string v )
{
Add( new KeyValuePair<string, string>( k, v ) );
}
internal IntPtr NativeArray;
private IntPtr m_pArrayEntries;
private int AppId = 0;
internal void Start()
{
var filters = this.Select( x =>
{
if ( x.Key == "appid" ) AppId = int.Parse( x.Value );
return new SteamNative.MatchMakingKeyValuePair_t()
{
Key = x.Key,
Value = x.Value
};
} ).ToArray();
int sizeOfMMKVP = Marshal.SizeOf(typeof(SteamNative.MatchMakingKeyValuePair_t));
NativeArray = Marshal.AllocHGlobal( Marshal.SizeOf( typeof( IntPtr ) ) * filters.Length );
m_pArrayEntries = Marshal.AllocHGlobal( sizeOfMMKVP * filters.Length );
for ( int i = 0; i < filters.Length; ++i )
{
Marshal.StructureToPtr( filters[i], new IntPtr( m_pArrayEntries.ToInt64() + ( i * sizeOfMMKVP ) ), false );
}
Marshal.WriteIntPtr( NativeArray, m_pArrayEntries );
}
internal void Free()
{
if ( m_pArrayEntries != IntPtr.Zero )
{
Marshal.FreeHGlobal( m_pArrayEntries );
}
if ( NativeArray != IntPtr.Zero )
{
Marshal.FreeHGlobal( NativeArray );
}
}
internal bool Test( gameserveritem_t info )
{
if ( AppId != 0 && AppId != info.AppID )
return false;
return true;
}
}
[StructLayout( LayoutKind.Sequential )]
private struct MatchPair
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string key;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string value;
}
public Request Internet( Filter filter = null )
{
if ( filter == null )
{
filter = new Filter();
filter.Add( "appid", client.AppId.ToString() );
}
filter.Start();
var request = new Request( client );
request.Filter = filter;
request.AddRequest( client.native.servers.RequestInternetServerList( client.AppId, filter.NativeArray, (uint) filter.Count, IntPtr.Zero ) );
filter.Free();
return request;
}
/// <summary>
/// Query a list of addresses. No filters applied.
/// </summary>
public Request Custom( IEnumerable<string> serverList )
{
var request = new Request( client );
request.ServerList = serverList;
request.StartCustomQuery();
return request;
}
/// <summary>
/// Request a list of servers we've been on. History isn't applied automatically
/// You need to call server.AddtoHistoryList() when you join a server etc.
/// </summary>
public Request History( Filter filter = null )
{
if ( filter == null )
{
filter = new Filter();
filter.Add( "appid", client.AppId.ToString() );
}
filter.Start();
var request = new Request( client );
request.Filter = filter;
request.AddRequest( client.native.servers.RequestHistoryServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) );
filter.Free();
return request;
}
/// <summary>
/// Request a list of servers we've favourited
/// </summary>
public Request Favourites( Filter filter = null )
{
if ( filter == null )
{
filter = new Filter();
filter.Add( "appid", client.AppId.ToString() );
}
filter.Start();
var request = new Request( client );
request.Filter = filter;
request.AddRequest( client.native.servers.RequestFavoritesServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) );
filter.Free();
return request;
}
/// <summary>
/// Request a list of servers that our friends are on
/// </summary>
public Request Friends( Filter filter = null )
{
if ( filter == null )
{
filter = new Filter();
filter.Add( "appid", client.AppId.ToString() );
}
filter.Start();
var request = new Request( client );
request.Filter = filter;
request.AddRequest( client.native.servers.RequestFriendsServerList( client.AppId, filter.NativeArray, (uint)filter.Count, IntPtr.Zero ) );
filter.Free();
return request;
}
/// <summary>
/// Request a list of servers that are running on our LAN
/// </summary>
public Request Local( Filter filter = null )
{
if ( filter == null )
{
filter = new Filter();
filter.Add( "appid", client.AppId.ToString() );
}
filter.Start();
var request = new Request( client );
request.Filter = filter;
request.AddRequest( client.native.servers.RequestLANServerList( client.AppId, IntPtr.Zero ) );
filter.Free();
return request;
}
internal bool IsFavourite( Server server )
{
ulong encoded = Utility.IpToInt32( server.Address );
encoded = encoded << 32;
encoded = encoded | (uint)server.ConnectionPort;
return FavouriteHash.Contains( encoded );
}
internal bool IsHistory( Server server )
{
ulong encoded = Utility.IpToInt32( server.Address );
encoded = encoded << 32;
encoded = encoded | (uint)server.ConnectionPort;
return HistoryHash.Contains( encoded );
}
}
}

View File

@ -1,121 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public class Stats : IDisposable
{
internal Client client;
internal Stats( Client c )
{
client = c;
}
public bool StoreStats()
{
return client.native.userstats.StoreStats();
}
public void UpdateStats()
{
client.native.userstats.RequestCurrentStats();
}
public void UpdateGlobalStats( int days = 1 )
{
client.native.userstats.GetNumberOfCurrentPlayers();
client.native.userstats.RequestGlobalAchievementPercentages();
client.native.userstats.RequestGlobalStats( days );
}
public int GetInt( string name )
{
int data = 0;
client.native.userstats.GetStat( name, out data );
return data;
}
public long GetGlobalInt( string name )
{
long data = 0;
client.native.userstats.GetGlobalStat( name, out data );
return data;
}
public float GetFloat( string name )
{
float data = 0;
client.native.userstats.GetStat0( name, out data );
return data;
}
public double GetGlobalFloat( string name )
{
double data = 0;
client.native.userstats.GetGlobalStat0( name, out data );
return data;
}
/// <summary>
/// Set a stat value. This will automatically call StoreStats() after a successful call
/// unless you pass false as the last argument.
/// </summary>
public bool Set( string name, int value, bool store = true )
{
var r = client.native.userstats.SetStat( name, value );
if ( store )
{
return r && client.native.userstats.StoreStats();
}
return r;
}
/// <summary>
/// Set a stat value. This will automatically call StoreStats() after a successful call
/// unless you pass false as the last argument.
/// </summary>
public bool Set( string name, float value, bool store = true )
{
var r = client.native.userstats.SetStat0( name, value );
if ( store )
{
return r && client.native.userstats.StoreStats();
}
return r;
}
/// <summary>
/// Adds this amount to the named stat. Internally this calls Get() and adds
/// to that value. Steam doesn't provide a mechanism for atomically increasing
/// stats like this, this functionality is added here as a convenience.
/// </summary>
public bool Add( string name, int amount = 1, bool store = true )
{
var val = GetInt( name );
val += amount;
return Set( name, val, store );
}
/// <summary>
/// Practically wipes the slate clean for this user. If includeAchievements is true, will wipe
/// any achievements too.
/// </summary>
/// <returns></returns>
public bool ResetAll( bool includeAchievements )
{
return client.native.userstats.ResetAllStats( includeAchievements );
}
public void Dispose()
{
client = null;
}
}
}

View File

@ -1,136 +0,0 @@
using SteamNative;
namespace Facepunch.Steamworks
{
public class SteamFriend
{
/// <summary>
/// Steam Id
/// </summary>
public ulong Id { get; internal set; }
/// <summary>
/// Return true if blocked
/// </summary>
public bool IsBlocked => relationship == FriendRelationship.Blocked;
/// <summary>
/// Return true if is a friend. Returns false if blocked, request etc.
/// </summary>
public bool IsFriend => relationship == FriendRelationship.Friend;
/// <summary>
/// Their current display name
/// </summary>
public string Name;
/// <summary>
/// Returns true if this friend is online
/// </summary>
public bool IsOnline => personaState != PersonaState.Offline;
/// <summary>
/// Returns true if this friend is marked as away
/// </summary>
public bool IsAway => personaState == PersonaState.Away;
/// <summary>
/// Returns true if this friend is marked as busy
/// </summary>
public bool IsBusy => personaState == PersonaState.Busy;
/// <summary>
/// Returns true if this friend is marked as snoozing
/// </summary>
public bool IsSnoozing => personaState == PersonaState.Snooze;
/// <summary>
/// Returns true if this friend is online and playing this game
/// </summary>
public bool IsPlayingThisGame => CurrentAppId == Client.AppId;
/// <summary>
/// Returns true if this friend is online and playing this game
/// </summary>
public bool IsPlaying => CurrentAppId != 0;
/// <summary>
/// The AppId this guy is playing
/// </summary>
public ulong CurrentAppId { get; internal set; }
public uint ServerIp { get; internal set; }
public int ServerGamePort { get; internal set; }
public int ServerQueryPort { get; internal set; }
public ulong ServerLobbyId { get; internal set; }
internal Client Client { get; set; }
private PersonaState personaState;
private FriendRelationship relationship;
/// <summary>
/// Returns null if the value doesn't exist
/// </summary>
public string GetRichPresence( string key )
{
var val = Client.native.friends.GetFriendRichPresence( Id, key );
if ( string.IsNullOrEmpty( val ) ) return null;
return val;
}
/// <summary>
/// Update this friend, request the latest data from Steam's servers
/// </summary>
public void Refresh()
{
Name = Client.native.friends.GetFriendPersonaName( Id );
relationship = Client.native.friends.GetFriendRelationship( Id );
personaState = Client.native.friends.GetFriendPersonaState( Id );
CurrentAppId = 0;
ServerIp = 0;
ServerGamePort = 0;
ServerQueryPort = 0;
ServerLobbyId = 0;
var gameInfo = new SteamNative.FriendGameInfo_t();
if ( Client.native.friends.GetFriendGamePlayed( Id, ref gameInfo ) && gameInfo.GameID > 0 )
{
CurrentAppId = gameInfo.GameID;
ServerIp = gameInfo.GameIP;
ServerGamePort = gameInfo.GamePort;
ServerQueryPort = gameInfo.QueryPort;
ServerLobbyId = gameInfo.SteamIDLobby;
}
Client.native.friends.RequestFriendRichPresence( Id );
}
/// <summary>
/// This will return null if you don't have the target user's avatar in your cache.
/// Which usually happens for people not on your friends list.
/// </summary>
public Image GetAvatar( Friends.AvatarSize size )
{
return Client.Friends.GetCachedAvatar( size, Id );
}
/// <summary>
/// Invite this friend to the game that we are playing
/// </summary>
public bool InviteToGame(string Text)
{
return Client.native.friends.InviteUserToGame(Id, Text);
}
/// <summary>
/// Sends a message to a Steam friend. Returns true if success
/// </summary>
public bool SendMessage( string message )
{
return Client.native.friends.ReplyToFriendMessage( Id, message );
}
}
}

View File

@ -1,50 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using SteamNative;
namespace Facepunch.Steamworks
{
public class User : IDisposable
{
internal Client client;
internal Dictionary<string, string> richPresence = new Dictionary<string, string>();
internal User( Client c )
{
client = c;
}
public void Dispose()
{
client = null;
}
public string GetRichPresence( string key )
{
string val = null;
if ( richPresence.TryGetValue( key, out val ) )
return val;
return null;
}
public void SetRichPresence( string key, string value )
{
richPresence[key] = value;
client.native.friends.SetRichPresence( key, value );
}
public void ClearRichPresence()
{
richPresence.Clear();
client.native.friends.ClearRichPresence();
}
}
}

View File

@ -1,182 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace Facepunch.Steamworks
{
public class Voice
{
const int ReadBufferSize = 1024 * 128;
internal Client client;
internal byte[] ReadCompressedBuffer = new byte[ReadBufferSize];
internal byte[] ReadUncompressedBuffer = new byte[ReadBufferSize];
internal byte[] UncompressBuffer = new byte[1024 * 256];
public Action<byte[], int> OnCompressedData;
public Action<byte[], int> OnUncompressedData;
private System.Diagnostics.Stopwatch UpdateTimer = System.Diagnostics.Stopwatch.StartNew();
/// <summary>
/// Returns the optimal sample rate for voice - according to Steam
/// </summary>
public uint OptimalSampleRate
{
get { return client.native.user.GetVoiceOptimalSampleRate(); }
}
private bool _wantsrecording = false;
/// <summary>
/// If set to true we are listening to the mic.
/// You should usually toggle this with the press of a key for push to talk.
/// </summary>
public bool WantsRecording
{
get { return _wantsrecording; }
set
{
_wantsrecording = value;
if ( value )
{
client.native.user.StartVoiceRecording();
}
else
{
client.native.user.StopVoiceRecording();
}
}
}
/// <summary>
/// The last time voice was detected, recorded
/// </summary>
public DateTime LastVoiceRecordTime { get; private set; }
public TimeSpan TimeSinceLastVoiceRecord { get { return DateTime.Now.Subtract( LastVoiceRecordTime ); } }
public bool IsRecording = false;
/// <summary>
/// If set we will capture the audio at this rate. If unset (set to 0) will capture at OptimalSampleRate
/// </summary>
public uint DesiredSampleRate = 0;
internal Voice( Client client )
{
this.client = client;
}
/// <summary>
/// This gets called inside Update - so there's no need to call this manually if you're calling update
/// </summary>
public unsafe void Update()
{
if ( OnCompressedData == null && OnUncompressedData == null )
return;
if ( UpdateTimer.Elapsed.TotalSeconds < 1.0f / 10.0f )
return;
UpdateTimer.Reset();
UpdateTimer.Start();
uint bufferRegularLastWrite = 0;
uint bufferCompressedLastWrite = 0;
var result = client.native.user.GetAvailableVoice( out bufferCompressedLastWrite, out bufferRegularLastWrite, DesiredSampleRate == 0 ? OptimalSampleRate : DesiredSampleRate );
if ( result == SteamNative.VoiceResult.NotRecording || result == SteamNative.VoiceResult.NotInitialized )
{
IsRecording = false;
return;
}
fixed (byte* compressedPtr = ReadCompressedBuffer)
fixed (byte* uncompressedPtr = ReadUncompressedBuffer)
{
result = client.native.user.GetVoice( OnCompressedData != null, (IntPtr) compressedPtr, ReadBufferSize, out bufferCompressedLastWrite,
OnUncompressedData != null, (IntPtr) uncompressedPtr, ReadBufferSize, out bufferRegularLastWrite,
DesiredSampleRate == 0 ? OptimalSampleRate : DesiredSampleRate );
}
IsRecording = true;
if ( result == SteamNative.VoiceResult.OK )
{
if ( OnCompressedData != null && bufferCompressedLastWrite > 0 )
{
OnCompressedData( ReadCompressedBuffer, (int)bufferCompressedLastWrite );
}
if ( OnUncompressedData != null && bufferRegularLastWrite > 0 )
{
OnUncompressedData( ReadUncompressedBuffer, (int)bufferRegularLastWrite );
}
LastVoiceRecordTime = DateTime.Now;
}
if ( result == SteamNative.VoiceResult.NotRecording ||
result == SteamNative.VoiceResult.NotInitialized )
IsRecording = false;
}
public bool Decompress( byte[] input, MemoryStream output, uint samepleRate = 0 )
{
return Decompress( input, 0, input.Length, output, samepleRate );
}
public bool Decompress( byte[] input, int inputsize, MemoryStream output, uint samepleRate = 0 )
{
return Decompress( input, 0, inputsize, output, samepleRate );
}
public unsafe bool Decompress( byte[] input, int inputoffset, int inputsize, MemoryStream output, uint samepleRate = 0 )
{
if ( inputoffset < 0 || inputoffset >= input.Length )
throw new ArgumentOutOfRangeException( "inputoffset" );
if ( inputsize <= 0 || inputoffset + inputsize > input.Length )
throw new ArgumentOutOfRangeException( "inputsize" );
fixed ( byte* p = input )
{
return Decompress( (IntPtr)p, inputoffset, inputsize, output, samepleRate );
}
}
private unsafe bool Decompress( IntPtr input, int inputoffset, int inputsize, MemoryStream output, uint samepleRate = 0 )
{
if ( samepleRate == 0 )
samepleRate = OptimalSampleRate;
uint bytesOut = 0;
SteamNative.VoiceResult result = SteamNative.VoiceResult.NoData;
fixed ( byte* outBuf = UncompressBuffer )
{
result = client.native.user.DecompressVoice( (IntPtr)(((byte*)input) + inputoffset), (uint)inputsize, (IntPtr)outBuf, (uint)UncompressBuffer.Length, out bytesOut, samepleRate );
}
if ( result == SteamNative.VoiceResult.OK )
{
output.Write( (byte[])UncompressBuffer, 0, (int)bytesOut );
return true;
}
return false;
}
}
}

View File

@ -1,74 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Facepunch.Steamworks
{
public static class Config
{
/// <summary>
/// Should be called before creating any interfaces, to configure Steam for Unity.
/// </summary>
/// <param name="platform">Please pass in Application.platform.ToString()</param>
public static void ForUnity( string platform )
{
//
// Windows Config
//
if ( platform == "WindowsEditor" || platform == "WindowsPlayer" )
{
ForcePlatform( OperatingSystem.Windows, IntPtr.Size == 4 ? Architecture.x86 : Architecture.x64 );
}
if ( platform == "OSXEditor" || platform == "OSXPlayer" || platform == "OSXDashboardPlayer" )
{
ForcePlatform( OperatingSystem.Osx, IntPtr.Size == 4 ? Architecture.x86 : Architecture.x64 );
}
if ( platform == "LinuxPlayer" || platform == "LinuxEditor" )
{
ForcePlatform( OperatingSystem.Linux, IntPtr.Size == 4 ? Architecture.x86 : Architecture.x64 );
}
IsUnity = true;
UseThisCall = true;
Console.WriteLine( "Facepunch.Steamworks Unity: " + platform );
Console.WriteLine( "Facepunch.Steamworks Os: " + SteamNative.Platform.Os );
Console.WriteLine( "Facepunch.Steamworks Arch: " + SteamNative.Platform.Arch );
}
/// <summary>
/// Some platforms allow/need CallingConvention.ThisCall. If you're crashing with argument null
/// errors on certain platforms, try flipping this to true.
///
/// I owe this logic to Riley Labrecque's hard work on Steamworks.net - I don't have the knowledge
/// or patience to find this shit on my own, so massive thanks to him. And also massive thanks to him
/// for releasing his shit open source under the MIT license so we can all learn and iterate.
///
/// </summary>
public static bool UseThisCall { get; set; } = SteamNative.Platform.Os == OperatingSystem.Windows;
/// <summary>
/// Should be true if we're using Unity
/// </summary>
internal static bool IsUnity { get; set; }
/// <summary>
/// You can force the platform to a particular one here.
/// This is useful if you're on OSX because some versions of mono don't have a way
/// to tell which platform we're running
/// </summary>
public static void ForcePlatform( Facepunch.Steamworks.OperatingSystem os, Facepunch.Steamworks.Architecture arch )
{
SteamNative.Platform.Os = os;
SteamNative.Platform.Arch = arch;
}
}
}

View File

@ -0,0 +1,107 @@
namespace Steamworks.Data
{
/// High level connection status
public enum ConnectionState
{
/// Dummy value used to indicate an error condition in the API.
/// Specified connection doesn't exist or has already been closed.
None = 0,
/// We are trying to establish whether peers can talk to each other,
/// whether they WANT to talk to each other, perform basic auth,
/// and exchange crypt keys.
///
/// - For connections on the "client" side (initiated locally):
/// We're in the process of trying to establish a connection.
/// Depending on the connection type, we might not know who they are.
/// Note that it is not possible to tell if we are waiting on the
/// network to complete handshake packets, or for the application layer
/// to accept the connection.
///
/// - For connections on the "server" side (accepted through listen socket):
/// We have completed some basic handshake and the client has presented
/// some proof of identity. The connection is ready to be accepted
/// using AcceptConnection().
///
/// In either case, any unreliable packets sent now are almost certain
/// to be dropped. Attempts to receive packets are guaranteed to fail.
/// You may send messages if the send mode allows for them to be queued.
/// but if you close the connection before the connection is actually
/// established, any queued messages will be discarded immediately.
/// (We will not attempt to flush the queue and confirm delivery to the
/// remote host, which ordinarily happens when a connection is closed.)
Connecting = 1,
/// Some connection types use a back channel or trusted 3rd party
/// for earliest communication. If the server accepts the connection,
/// then these connections switch into the rendezvous state. During this
/// state, we still have not yet established an end-to-end route (through
/// the relay network), and so if you send any messages unreliable, they
/// are going to be discarded.
FindingRoute = 2,
/// We've received communications from our peer (and we know
/// who they are) and are all good. If you close the connection now,
/// we will make our best effort to flush out any reliable sent data that
/// has not been acknowledged by the peer. (But note that this happens
/// from within the application process, so unlike a TCP connection, you are
/// not totally handing it off to the operating system to deal with it.)
Connected = 3,
/// Connection has been closed by our peer, but not closed locally.
/// The connection still exists from an API perspective. You must close the
/// handle to free up resources. If there are any messages in the inbound queue,
/// you may retrieve them. Otherwise, nothing may be done with the connection
/// except to close it.
///
/// This stats is similar to CLOSE_WAIT in the TCP state machine.
ClosedByPeer = 4,
/// A disruption in the connection has been detected locally. (E.g. timeout,
/// local internet connection disrupted, etc.)
///
/// The connection still exists from an API perspective. You must close the
/// handle to free up resources.
///
/// Attempts to send further messages will fail. Any remaining received messages
/// in the queue are available.
ProblemDetectedLocally = 5,
//
// The following values are used internally and will not be returned by any API.
// We document them here to provide a little insight into the state machine that is used
// under the hood.
//
/// We've disconnected on our side, and from an API perspective the connection is closed.
/// No more data may be sent or received. All reliable data has been flushed, or else
/// we've given up and discarded it. We do not yet know for sure that the peer knows
/// the connection has been closed, however, so we're just hanging around so that if we do
/// get a packet from them, we can send them the appropriate packets so that they can
/// know why the connection was closed (and not have to rely on a timeout, which makes
/// it appear as if something is wrong).
FinWait = -1,
/// We've disconnected on our side, and from an API perspective the connection is closed.
/// No more data may be sent or received. From a network perspective, however, on the wire,
/// we have not yet given any indication to the peer that the connection is closed.
/// We are in the process of flushing out the last bit of reliable data. Once that is done,
/// we will inform the peer that the connection has been closed, and transition to the
/// FinWait state.
///
/// Note that no indication is given to the remote host that we have closed the connection,
/// until the data has been flushed. If the remote host attempts to send us data, we will
/// do whatever is necessary to keep the connection alive until it can be closed properly.
/// But in fact the data will be discarded, since there is no way for the application to
/// read it back. Typically this is not a problem, as application protocols that utilize
/// the lingering functionality are designed for the remote host to wait for the response
/// before sending any more data.
Linger = -2,
/// Connection is completely inactive and ready to be destroyed
Dead = -3,
Force32Bit = 0x7fffffff
};
}

View File

@ -0,0 +1,17 @@
namespace Steamworks.Data
{
enum DebugOutputType : int
{
None = 0,
Bug = 1, // You used the API incorrectly, or an internal error happened
Error = 2, // Run-time error condition that isn't the result of a bug. (E.g. we are offline, cannot bind a port, etc)
Important = 3, // Nothing is wrong, but this is an important notification
Warning = 4,
Msg = 5, // Recommended amount
Verbose = 6, // Quite a bit
Debug = 7, // Practically everything
Everything = 8, // Wall of text, detailed packet contents breakdown, etc
Force32Bit = 0x7fffffff
};
}

View File

@ -0,0 +1,20 @@
namespace Steamworks.Data
{
public enum LeaderboardDisplay : int
{
/// <summary>
/// The score is just a simple numerical value
/// </summary>
Numeric = 1,
/// <summary>
/// The score represents a time, in seconds
/// </summary>
TimeSeconds = 2,
/// <summary>
/// The score represents a time, in milliseconds
/// </summary>
TimeMilliSeconds = 3,
}
}

View File

@ -0,0 +1,15 @@
namespace Steamworks.Data
{
public enum LeaderboardSort : int
{
/// <summary>
/// The top-score is the lowest number
/// </summary>
Ascending = 1,
/// <summary>
/// The top-score is the highest number
/// </summary>
Descending = 2,
}
}

Some files were not shown because too many files have changed in this diff Show More