mirror of
https://github.com/Facepunch/Facepunch.Steamworks.git
synced 2024-12-26 06:35:49 +03:00
Added leaderboards
This commit is contained in:
parent
5426339bd0
commit
45024c57f3
93
Facepunch.Steamworks.Test/Client/Leaderboard.cs
Normal file
93
Facepunch.Steamworks.Test/Client/Leaderboard.cs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
|
||||||
|
namespace Facepunch.Steamworks.Test
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
[DeploymentItem( "steam_api.dll" )]
|
||||||
|
[DeploymentItem( "steam_api64.dll" )]
|
||||||
|
[DeploymentItem( "steam_appid.txt" )]
|
||||||
|
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 );
|
||||||
|
|
||||||
|
while ( !board.IsValid )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
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, false, 86275309, 7, 8, 9 );
|
||||||
|
|
||||||
|
board.FetchScores( Steamworks.Leaderboard.RequestType.Global, 0, 20 );
|
||||||
|
|
||||||
|
while ( board.IsQuerying )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 AddScores()
|
||||||
|
{
|
||||||
|
using ( var client = new Steamworks.Client( 252490 ) )
|
||||||
|
{
|
||||||
|
var board = client.GetLeaderboard( "TestLeaderboard", Steamworks.Client.LeaderboardSortMethod.Ascending, Steamworks.Client.LeaderboardDisplayType.Numeric );
|
||||||
|
|
||||||
|
while ( !board.IsValid )
|
||||||
|
{
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.IsTrue( board.IsValid );
|
||||||
|
Assert.IsFalse( board.IsError );
|
||||||
|
|
||||||
|
|
||||||
|
board.AddScore( true, false, 1234 );
|
||||||
|
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
|
||||||
|
board.AddScore( true, true, 34566 );
|
||||||
|
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
|
||||||
|
board.AddScore( true, false, 86275309, 7, 8, 9, 7, 4, 7, 98, 24, 5, 76, 124, 6 );
|
||||||
|
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
|
||||||
|
board.AddScore( false, true, 86275309, 7, 8, 9, 7, 4, 7, 98, 24, 5, 76, 124, 6 );
|
||||||
|
|
||||||
|
Thread.Sleep( 10 );
|
||||||
|
client.Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -93,6 +93,7 @@
|
|||||||
</Choose>
|
</Choose>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Client\Client.cs" />
|
<Compile Include="Client\Client.cs" />
|
||||||
|
<Compile Include="Client\Leaderboard.cs" />
|
||||||
<Compile Include="Client\Voice.cs" />
|
<Compile Include="Client\Voice.cs" />
|
||||||
<Compile Include="Client\Inventory.cs" />
|
<Compile Include="Client\Inventory.cs" />
|
||||||
<Compile Include="Client\Workshop.cs" />
|
<Compile Include="Client\Workshop.cs" />
|
||||||
|
@ -106,5 +106,28 @@ public override void Dispose()
|
|||||||
|
|
||||||
base.Dispose();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
175
Facepunch.Steamworks/Client/Leaderboard.cs
Normal file
175
Facepunch.Steamworks/Client/Leaderboard.cs
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using SteamNative;
|
||||||
|
|
||||||
|
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 only users that are close to you geographically
|
||||||
|
/// </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;
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void OnBoardCreated( LeaderboardFindResult_t result, bool error )
|
||||||
|
{
|
||||||
|
if ( error || ( result.LeaderboardFound == 0 ) )
|
||||||
|
{
|
||||||
|
IsError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BoardId = result.SteamLeaderboard;
|
||||||
|
|
||||||
|
if ( IsValid )
|
||||||
|
{
|
||||||
|
Name = client.native.userstats.GetLeaderboardName( BoardId );
|
||||||
|
TotalEntries = client.native.userstats.GetLeaderboardEntryCount( BoardId );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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.
|
||||||
|
/// </summary>
|
||||||
|
public void AddScore( bool replaceOldScore, bool onlyIfBeatsOldScore, int score, params int[] subscores )
|
||||||
|
{
|
||||||
|
if ( !IsValid ) return;
|
||||||
|
|
||||||
|
var flags = LeaderboardUploadScoreMethod.None;
|
||||||
|
|
||||||
|
if ( replaceOldScore ) flags |= LeaderboardUploadScoreMethod.ForceUpdate;
|
||||||
|
if ( onlyIfBeatsOldScore ) flags |= LeaderboardUploadScoreMethod.KeepBest;
|
||||||
|
|
||||||
|
client.native.userstats.UploadLeaderboardScore( BoardId, flags, score, subscores, subscores.Length );
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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 OnScores( LeaderboardScoresDownloaded_t result, bool error )
|
||||||
|
{
|
||||||
|
IsQuerying = false;
|
||||||
|
|
||||||
|
if ( client == null ) return;
|
||||||
|
|
||||||
|
if ( error )
|
||||||
|
return;
|
||||||
|
|
||||||
|
var list = new List<Entry>();
|
||||||
|
|
||||||
|
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 ) )
|
||||||
|
list.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 )
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
/// <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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -115,6 +115,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="BaseSteamworks.cs" />
|
<Compile Include="BaseSteamworks.cs" />
|
||||||
<Compile Include="Callbacks\Index.cs" />
|
<Compile Include="Callbacks\Index.cs" />
|
||||||
|
<Compile Include="Client\Leaderboard.cs" />
|
||||||
<Compile Include="Interfaces\Inventory.Item.cs" />
|
<Compile Include="Interfaces\Inventory.Item.cs" />
|
||||||
<Compile Include="Interfaces\Inventory.Result.cs" />
|
<Compile Include="Interfaces\Inventory.Result.cs" />
|
||||||
<Compile Include="Interfaces\Networking.cs" />
|
<Compile Include="Interfaces\Networking.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user