Facepunch.Steamworks Wiki

Leaderboards

Creating a Leaderboard

Creating a leaderboard is really easy.

using Steamworks; using Steamworks.Data; ... var leaderboard = await SteamUserStats.FindOrCreateLeaderboardAsync( "MyLeaderboard", LeaderboardSort.Ascending, LeaderboardDisplay.Numeric );

Here you've created a leaderboard named "MyLeaderboard" which is sorted in ascending (highest first) and is number based (high score etc) rather than time based (fastest lap etc).

Getting a Leaderboard

You can safely get a leaderboard with the same function. If you only want to get one that exists you can use:

var leaderboard = await SteamUserStats.FindLeaderboardAsync( "MyLeaderboard" );
FindLeaderboardAsync and FindOrCreateLeaderboardAsync return a nullable. If for whatever reason the board cannot be found - it'll be null. This means you should check it first via leaderboard.HasValue and then the real leaderboard is in leaderboard.Value.

Submitting a Score

var result = await lb.SubmitScoreAsync( 576 );

This function will only replace your last score if the new one is better. On success (result.HasValue) this function will return a Data.LeaderboardUpdate.

You can force your score to be replace, even if it's worse, using:

var result = await lb.ReplaceScore( 576 );

Getting Scores

// Get top 20 scores LeaderboardEntry[] globalScores = await lb.Value.GetScoresAsync( 20 ); foreach ( LeaderboardEntry e in globalScores) { Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" ); } // Get scores from friends LeaderboardEntry[] friendScores = await lb.Value.GetScoresFromFriendsAsync(); foreach ( LeaderboardEntry e in friendScores ) { Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" ); } // Get scores around current user LeaderboardEntry[] surroundScores = await lb.Value.GetScoresAroundUserAsync( -10, 10 ); foreach ( LeaderboardEntry e in surroundScores ) { Console.WriteLine( $"{e.GlobalRank}: {e.Score} {e.User}" ); }

Example

using System; using System.Threading.Tasks; using Steamworks; using Steamworks.Data; using UnityEngine; public static class SteamLeaderBoardSystem { /// <summary> /// This function will only replace your last score if the new one is better. /// </summary> /// <param name="leaderboard"></param> /// <param name="value"></param> /// <param name="details"></param> public static async Task SubmitLeaderboard(Steamworks.Data.Leaderboard leaderboard, int value, int[] details = null) { var leaderboardUpdate = await leaderboard.SubmitScoreAsync(value, details ?? Array.Empty<int>()); if (!leaderboardUpdate.HasValue) { Debug.LogError("leaderboardUpdate is null"); return; } Debug.Log(leaderboardUpdate.Value); } /// <summary> /// Force your score to be replaced /// </summary> /// <param name="leaderboard"></param> /// <param name="value"></param> /// <param name="details"></param> public static async Task ReplaceLeaderboard(Steamworks.Data.Leaderboard leaderboard, int value, int[] details = null) { var leaderboardUpdate = await leaderboard.ReplaceScore(value, details ?? Array.Empty<int>()); if (!leaderboardUpdate.HasValue) { Debug.LogError("leaderboardUpdate is null"); return; } Debug.Log(leaderboardUpdate.Value); } public static async Task<Steamworks.Data.Leaderboard?> GetLeaderBoards(string lbName) { try { return await FindOrCreateLeaderboardAsync(lbName); } catch (Exception e) { Debug.LogError(e); } return null; } private static async Task<Steamworks.Data.Leaderboard?> FindOrCreateLeaderboardAsync(string leaderboardName) { try { return await SteamUserStats.FindOrCreateLeaderboardAsync(leaderboardName, LeaderboardSort.Ascending, LeaderboardDisplay.Numeric); } catch (Exception e) { Debug.LogError(e); } return null; } }

Example usage of the example above

public class SteamLeaderBoard : MonoBehaviour { private const string LeaderboardName = "MyLeaderboard"; private Steamworks.Data.Leaderboard _lb; private async void Awake() { try { var lb = await SteamLeaderBoardSystem.GetLeaderBoards(LeaderboardName); if (lb.HasValue) _lb = lb.Value; else Debug.LogError("leaderboard did not have value"); } catch (Exception e) { Debug.LogError($"Error loading leaderboards: {e.Message}"); // Optionally, you could handle the exception, e.g., retry logic or fallback behavior } } #region TEST [ContextMenu("ReplaceScoreTest")] private void ReplaceScoreTest() { var entry = new LeaderboardScore(1234.1829f, 12345789); ReplaceSpeedScore(entry); } #endregion #region ReplaceScores private void ReplaceSpeedScore(LeaderboardScoreentry) { _ = SteamLeaderBoardSystem.ReplaceLeaderboard(_lb, entry.TimeI, entry.Details); } #endregion } // Struct to hold data for ease-of-use and re-use-ability public struct LeaderboardScore { public readonly int Score; public readonly int SomeOtherValue; public readonly int[] Details; public LeaderboardScore(int score, int someOtherValue) { Score = score; SomeOtherValue = someOtherValue; Details = new[] { someOtherValue }; } }