diff --git a/Facepunch.Steamworks.Test/UserStatsTest.cs b/Facepunch.Steamworks.Test/UserStatsTest.cs
index 7c5ad93..6d0b2c9 100644
--- a/Facepunch.Steamworks.Test/UserStatsTest.cs
+++ b/Facepunch.Steamworks.Test/UserStatsTest.cs
@@ -53,26 +53,102 @@ namespace Steamworks
[TestMethod]
public async Task CreateLeaderboard()
{
- var leaderboard = await SteamUserStats.FindOrCreateLeaderboard( "Testleaderboard", Data.LeaderboardSort.Descending, Data.LeaderboardDisplay.Numeric );
+ var leaderboard = await SteamUserStats.FindOrCreateLeaderboard( "Testleaderboard", Data.LeaderboardSort.Ascending, Data.LeaderboardDisplay.Numeric );
Assert.IsTrue( leaderboard.HasValue );
}
[TestMethod]
public async Task FindLeaderboard()
+ {
+ var leaderboard = await SteamUserStats.FindLeaderboard( "Testleaderboard" );
+ Assert.IsTrue( leaderboard.HasValue );
+ }
+
+ [TestMethod]
+ public async Task SubmitScore()
+ {
+ var leaderboard = await SteamUserStats.FindLeaderboard( "Testleaderboard" );
+ Assert.IsTrue( leaderboard.HasValue );
+
+ var result = await leaderboard.Value.SubmitScore( 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.FindLeaderboard( "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.FindLeaderboard( "Testleaderboard" );
+ Assert.IsTrue( leaderboard.HasValue );
+
+ // Get entries around user
+ var friendScores = await leaderboard.Value.GetScoresFromFriends();
+ Assert.IsNotNull( friendScores );
+
+ Console.WriteLine( $"" );
+ Console.WriteLine( $"Friend Scores:" );
+ foreach ( var e in friendScores )
+ {
+ Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" );
+ }
+ }
+
+ [TestMethod]
+ public async Task GetScoresAroundUserAsync()
+ {
+ var leaderboard = await SteamUserStats.FindLeaderboard( "Testleaderboard" );
+ Assert.IsTrue( leaderboard.HasValue );
+
+ // Get entries around user
+ var relativeScores = await leaderboard.Value.GetScoresAroundUserAsync( -5, 5 );
+ 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.FindLeaderboard( "Testleaderboard" );
Assert.IsTrue( leaderboard.HasValue );
// Get top 20 global scores
- var globalsScores = await leaderboard.Value.GetGlobalEntriesAsync( 20 );
+ 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}" );
}
-
}
}
diff --git a/Facepunch.Steamworks/Structs/Friend.cs b/Facepunch.Steamworks/Structs/Friend.cs
index d392533..c3cf09f 100644
--- a/Facepunch.Steamworks/Structs/Friend.cs
+++ b/Facepunch.Steamworks/Structs/Friend.cs
@@ -21,8 +21,25 @@ namespace Steamworks
return $"{Name} ({Id.ToString()})";
}
+
+ ///
+ /// Returns true if this is the local user
+ ///
+ public bool IsMe => Id == SteamClient.SteamId;
+
+ ///
+ /// Return true if this is a friend
+ ///
public bool IsFriend => Relationship == Relationship.Friend;
+
+ ///
+ /// Returns true if you have this user blocked
+ ///
public bool IsBlocked => Relationship == Relationship.Blocked;
+
+ ///
+ /// Return true if this user is playing the game we're running
+ ///
public bool IsPlayingThisGame => GameInfo?.GameID == SteamUtils.AppId;
///
diff --git a/Facepunch.Steamworks/Structs/Leaderboard.cs b/Facepunch.Steamworks/Structs/Leaderboard.cs
index 7efe010..1a5dc2f 100644
--- a/Facepunch.Steamworks/Structs/Leaderboard.cs
+++ b/Facepunch.Steamworks/Structs/Leaderboard.cs
@@ -19,11 +19,39 @@ namespace Steamworks.Data
public LeaderboardDisplay Display => SteamUserStats.Internal.GetLeaderboardDisplayType( Id );
static int[] detailsBuffer = new int[64];
+ static int[] noDetails = new int[0];
+
+ ///
+ /// Submit your score and replace your old score even if it was better
+ ///
+ public async Task ReplaceScore( int score, int[] details = null )
+ {
+ if ( details == null ) details = noDetails;
+
+ var r = await SteamUserStats.Internal.UploadLeaderboardScore( Id, LeaderboardUploadScoreMethod.ForceUpdate, score, details, details.Length );
+ if ( !r.HasValue ) return null;
+
+ return LeaderboardUpdate.From( r.Value );
+ }
+
+ ///
+ /// Submit your new score, but won't replace your high score if it's lower
+ ///
+ public async Task SubmitScore( int score, int[] details = null )
+ {
+ if ( details == null ) details = noDetails;
+
+ var r = await SteamUserStats.Internal.UploadLeaderboardScore( Id, LeaderboardUploadScoreMethod.KeepBest, score, details, details.Length );
+ if ( !r.HasValue ) return null;
+
+ return LeaderboardUpdate.From( r.Value );
+ }
+
///
/// Used to query for a sequential range of leaderboard entries by leaderboard Sort.
///
- public async Task GetGlobalEntriesAsync( int count, int offset = 1 )
+ public async Task GetScoresAsync( int count, int offset = 1 )
{
if ( offset <= 0 ) throw new System.ArgumentException( "Should be 1+", nameof( offset ) );
@@ -34,6 +62,33 @@ namespace Steamworks.Data
return await LeaderboardResultToEntries( r.Value );
}
+ ///
+ /// Used to retrieve leaderboard entries relative a user's entry. If there are not enough entries in the leaderboard
+ /// before or after the user's entry, Steam will adjust the range to try to return the number of entries requested.
+ /// For example, if the user is #1 on the leaderboard and start is set to -2, end is set to 2, Steam will return the first
+ /// 5 entries in the leaderboard. If The current user has no entry, this will return null.
+ ///
+ public async Task GetScoresAroundUserAsync( int start = -10, int end = 10 )
+ {
+ var r = await SteamUserStats.Internal.DownloadLeaderboardEntries( Id, LeaderboardDataRequest.GlobalAroundUser, start, end );
+ if ( !r.HasValue )
+ return null;
+
+ return await LeaderboardResultToEntries( r.Value );
+ }
+
+ ///
+ /// Used to retrieve all leaderboard entries for friends of the current user
+ ///
+ public async Task GetScoresFromFriends()
+ {
+ var r = await SteamUserStats.Internal.DownloadLeaderboardEntries( Id, LeaderboardDataRequest.Friends, 0, 0 );
+ if ( !r.HasValue )
+ return null;
+
+ return await LeaderboardResultToEntries( r.Value );
+ }
+
#region util
internal async Task LeaderboardResultToEntries( LeaderboardScoresDownloaded_t r )
{
diff --git a/Facepunch.Steamworks/Structs/LeaderboardUpdate.cs b/Facepunch.Steamworks/Structs/LeaderboardUpdate.cs
new file mode 100644
index 0000000..dc0eb12
--- /dev/null
+++ b/Facepunch.Steamworks/Structs/LeaderboardUpdate.cs
@@ -0,0 +1,22 @@
+using System.Linq;
+
+namespace Steamworks.Data
+{
+ public struct LeaderboardUpdate
+ {
+ public int Score;
+ public bool Changed;
+ public int NewGlobalRank;
+ public int OldGlobalRank;
+ public int RankChange => NewGlobalRank - OldGlobalRank;
+
+ internal static LeaderboardUpdate From( LeaderboardScoreUploaded_t e ) =>
+ new LeaderboardUpdate
+ {
+ Score = e.Score,
+ Changed = e.ScoreChanged == 1,
+ NewGlobalRank = e.GlobalRankNew,
+ OldGlobalRank = e.GlobalRankPrevious
+ };
+ }
+}
\ No newline at end of file