mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2025-01-27 22:18:11 +03:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
e4053e9b2a
3
.gitignore
vendored
3
.gitignore
vendored
@ -73,4 +73,5 @@ mscorlib.dll
|
||||
packages
|
||||
Generator/bin
|
||||
*.XML
|
||||
.vs
|
||||
.vs
|
||||
Facepunch.Steamworks.Test/bin/**
|
||||
|
5
CompileFix.bat
Normal file
5
CompileFix.bat
Normal 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
|
114
Facepunch.Steamworks.Test/AppTest.cs
Normal file
114
Facepunch.Steamworks.Test/AppTest.cs
Normal 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}" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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})" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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)" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
@ -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 :(" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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">
|
147
Facepunch.Steamworks.Test/Facepunch.Steamworks.TestWin64.csproj
Normal file
147
Facepunch.Steamworks.Test/Facepunch.Steamworks.TestWin64.csproj
Normal 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>
|
176
Facepunch.Steamworks.Test/FriendsTest.cs
Normal file
176
Facepunch.Steamworks.Test/FriendsTest.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
126
Facepunch.Steamworks.Test/GameServerTest.cs
Normal file
126
Facepunch.Steamworks.Test/GameServerTest.cs
Normal 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 );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
31
Facepunch.Steamworks.Test/InputTest.cs
Normal file
31
Facepunch.Steamworks.Test/InputTest.cs
Normal 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" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
222
Facepunch.Steamworks.Test/InventoryTest.cs
Normal file
222
Facepunch.Steamworks.Test/InventoryTest.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
287
Facepunch.Steamworks.Test/NetworkingSockets.cs
Normal file
287
Facepunch.Steamworks.Test/NetworkingSockets.cs
Normal 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" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
62
Facepunch.Steamworks.Test/NetworkingUtils.cs
Normal file
62
Facepunch.Steamworks.Test/NetworkingUtils.cs
Normal 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}" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
78
Facepunch.Steamworks.Test/RemoteStorageTest.cs
Normal file
78
Facepunch.Steamworks.Test/RemoteStorageTest.cs
Normal 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 )})" );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
229
Facepunch.Steamworks.Test/ServerlistTest.cs
Normal file
229
Facepunch.Steamworks.Test/ServerlistTest.cs
Normal 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}" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
105
Facepunch.Steamworks.Test/SteamMatchmakingTest.cs
Normal file
105
Facepunch.Steamworks.Test/SteamMatchmakingTest.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
Facepunch.Steamworks.Test/SteamNetworkingTest.cs
Normal file
37
Facepunch.Steamworks.Test/SteamNetworkingTest.cs
Normal 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 );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
182
Facepunch.Steamworks.Test/UgcEditor.cs
Normal file
182
Facepunch.Steamworks.Test/UgcEditor.cs
Normal 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 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
130
Facepunch.Steamworks.Test/UgcQuery.cs
Normal file
130
Facepunch.Steamworks.Test/UgcQuery.cs
Normal 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}" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
39
Facepunch.Steamworks.Test/UgcTest.cs
Normal file
39
Facepunch.Steamworks.Test/UgcTest.cs
Normal 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}" );
|
||||
}
|
||||
}
|
||||
}
|
197
Facepunch.Steamworks.Test/UserStatsTest.cs
Normal file
197
Facepunch.Steamworks.Test/UserStatsTest.cs
Normal 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]}" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
155
Facepunch.Steamworks.Test/UserTest.cs
Normal file
155
Facepunch.Steamworks.Test/UserTest.cs
Normal 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" ) ) )}" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
117
Facepunch.Steamworks.Test/UtilsTest.cs
Normal file
117
Facepunch.Steamworks.Test/UtilsTest.cs
Normal 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}" );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Facepunch.Steamworks.Test/bin/x64/Debug/steam_api64.dll
Normal file
BIN
Facepunch.Steamworks.Test/bin/x64/Debug/steam_api64.dll
Normal file
Binary file not shown.
@ -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>
|
@ -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
|
||||
|
@ -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 ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
43
Facepunch.Steamworks/Callbacks/Callback.cs
Normal file
43
Facepunch.Steamworks/Callbacks/Callback.cs
Normal 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()]" );
|
||||
};
|
||||
}
|
135
Facepunch.Steamworks/Callbacks/Event.cs
Normal file
135
Facepunch.Steamworks/Callbacks/Event.cs
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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
|
||||
};
|
||||
}
|
30
Facepunch.Steamworks/Classes/AuthTicket.cs
Normal file
30
Facepunch.Steamworks/Classes/AuthTicket.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
120
Facepunch.Steamworks/Classes/ConnectionInterface.cs
Normal file
120
Facepunch.Steamworks/Classes/ConnectionInterface.cs
Normal 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 )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
112
Facepunch.Steamworks/Classes/SocketInterface.cs
Normal file
112
Facepunch.Steamworks/Classes/SocketInterface.cs
Normal 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 )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
*/
|
||||
}
|
||||
}
|
@ -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
|
||||
*/
|
||||
}
|
||||
}
|
@ -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
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 ); }
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
107
Facepunch.Steamworks/Enum/ConnectionState.cs
Normal file
107
Facepunch.Steamworks/Enum/ConnectionState.cs
Normal 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
|
||||
};
|
||||
}
|
17
Facepunch.Steamworks/Enum/DebugOutputType.cs
Normal file
17
Facepunch.Steamworks/Enum/DebugOutputType.cs
Normal 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
|
||||
};
|
||||
}
|
20
Facepunch.Steamworks/Enum/LeaderboardDisplay.cs
Normal file
20
Facepunch.Steamworks/Enum/LeaderboardDisplay.cs
Normal 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,
|
||||
}
|
||||
}
|
15
Facepunch.Steamworks/Enum/LeaderboardSort.cs
Normal file
15
Facepunch.Steamworks/Enum/LeaderboardSort.cs
Normal 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
Loading…
x
Reference in New Issue
Block a user