How to do leaderboards in Steamworks.NET?
Asked Answered
C

1

6

I am trying to include leaderboards in my application (a game written in C#, using SteamWorks.NET and based on XNA).

Steam is initialized properly.

On gamestart I call:

SteamAPICall_t hSteamAPICall = SteamUserStats.FindLeaderboard("Most active beta testers");
leaderboard_BetaTesters_ResultFindLeaderboard = Callback<LeaderboardFindResult_t>.Create(OnLeaderboardFindResult_BetaTesters);

using

static private void OnLeaderboardFindResult_BetaTesters(LeaderboardFindResult_t pCallback)
{
// See if we encountered an error during the call
if (pCallback.m_bLeaderboardFound == 0)
  {
  Warning.Happened("Leaderboard could not be found / accessed");
  return;
  }
else
  {
  Write.Text("Steam leaderboad connected");
  }
  leaderboard_BetaTesters = pCallback.m_hSteamLeaderboard;
}

And in every Update() I call:

if (SystemLogic.SteamInitSuccessul()) SteamAPI.RunCallbacks();

However, OnLeaderboardFindResult_BetaTesters is never called. What am I doing wrong?

Cattleya answered 15/6, 2016 at 17:56 Comment(0)
S
7

I know is an old issue, but I've the same one just now.

I've the same issue when I tried to implement Steam leaderboards on Unity with Steamworks.NET. Finally I get it working from the original Steamworks C++ sample project. (The documentation for Steamworks.NET is really poor, like the original Steamworks c++ one, so you have to check the Steamworks c++ Sample Project to check how to use it)

You have a mistake, you have to use the "CallResult<>" class instead of the "Callback<>" one.

The following code allowed me to upload scores on Unity to a SteamLeaderboard:

using UnityEngine;
using Steamworks;
using System.Collections;
using System.Threading;

public class SteamLeaderboards : MonoBehaviour
{
    private const string s_leaderboardName = "StoryMode";
    private const ELeaderboardUploadScoreMethod s_leaderboardMethod = ELeaderboardUploadScoreMethod.k_ELeaderboardUploadScoreMethodKeepBest;

    private static SteamLeaderboard_t s_currentLeaderboard;
    private static bool s_initialized = false;
    private static CallResult<LeaderboardFindResult_t> m_findResult = new CallResult<LeaderboardFindResult_t>();
    private static CallResult<LeaderboardScoreUploaded_t> m_uploadResult = new CallResult<LeaderboardScoreUploaded_t>();


    public static void UpdateScore(int score)
    {
        if (!s_initialized)
        {
            UnityEngine.Debug.Log("Can't upload to the leaderboard because isn't loadded yet");
        }
        else
        {
            UnityEngine.Debug.Log("uploading score(" + score + ") to steam leaderboard(" + s_leaderboardName + ")");
            SteamAPICall_t hSteamAPICall = SteamUserStats.UploadLeaderboardScore(s_currentLeaderboard, s_leaderboardMethod, score, null, 0);
            m_uploadResult.Set(hSteamAPICall, OnLeaderboardUploadResult);
        }
    }

    public static void Init()
    {
        SteamAPICall_t hSteamAPICall = SteamUserStats.FindLeaderboard(s_leaderboardName);
        m_findResult.Set(hSteamAPICall, OnLeaderboardFindResult);
        InitTimer();
    }

    static private void OnLeaderboardFindResult(LeaderboardFindResult_t pCallback, bool failure)
    {
        UnityEngine.Debug.Log("STEAM LEADERBOARDS: Found - " + pCallback.m_bLeaderboardFound + " leaderboardID - " + pCallback.m_hSteamLeaderboard.m_SteamLeaderboard);
        s_currentLeaderboard = pCallback.m_hSteamLeaderboard;
        s_initialized = true;
    }

    static private void OnLeaderboardUploadResult(LeaderboardScoreUploaded_t pCallback, bool failure)
    {
        UnityEngine.Debug.Log("STEAM LEADERBOARDS: failure - " + failure + " Completed - " + pCallback.m_bSuccess + " NewScore: " + pCallback.m_nGlobalRankNew + " Score " + pCallback.m_nScore + " HasChanged - " + pCallback.m_bScoreChanged);
    }



    private static Timer timer1; 
    public static void InitTimer()
    {
        timer1 = new Timer(timer1_Tick, null,0,1000);
    }

    private static void timer1_Tick(object state)
    {
        SteamAPI.RunCallbacks(); 
    }
}

*I have edited several times this code without compile it, and maybe contains any syntax error, but the implementation should be fine

** Also remember this code has been used on Unity 4, but the Unity classes are used only for "console log" messages and for the last two methods "call each x miliseconds the SteamAPI.RunCallbacks() method"

Snodgrass answered 15/7, 2016 at 15:41 Comment(3)
One thing to add, if you want to create the leaderboard you can use something like FindOrCreateLeaderboard(s_leaderboardName, ELeaderboardSortMethod.k_ELeaderboardSortMethodDescending, ELeaderboardDisplayType.k_ELeaderboardDisplayTypeNumeric); instead of FindLeaderboard() The list of enums you need to supply as args 2 and 3 I found here: github.com/rlabrecque/Steamworks.NET/blob/…Irvin
This is great thank you, ICoso. Pardon my noobness but how should one wait for the Init() to finish before calling UpdateScore()?Ambivalence
@ChrisEmerson: I didn't worked with steam anymore, but as I see on the code, the UpdateScore method won't do anything until "s_initialized" is true, which becomes true when the FindLeaderboard callback is triggered (OnLeaderboardFindResult). So when Init method finishes, the UpdateScore method isn't available yet, since is waiting for the asynchronous "OnLeaderboardFindResult" callback. if you need you can add a bool method to check if the UpdateScore is available (if s_initialized value is true)Snodgrass

© 2022 - 2024 — McMap. All rights reserved.