From ddd5cc03f3f7ce4678250d3e125d3b836c2a7268 Mon Sep 17 00:00:00 2001 From: Garry Newman Date: Wed, 17 Apr 2019 10:34:47 +0100 Subject: [PATCH] Leaderboard, more entries and submit scores --- Facepunch.Steamworks.Test/UserStatsTest.cs | 82 ++++++++++++++++++- Facepunch.Steamworks/Structs/Friend.cs | 17 ++++ Facepunch.Steamworks/Structs/Leaderboard.cs | 57 ++++++++++++- .../Structs/LeaderboardUpdate.cs | 22 +++++ 4 files changed, 174 insertions(+), 4 deletions(-) create mode 100644 Facepunch.Steamworks/Structs/LeaderboardUpdate.cs 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