如何在Unity中使用Steamworks.NET处理多个排行榜
Steamworks.NET Unity 多排行榜处理方案
你的问题核心是复用同一个CallResult实例时,多次调用Set()会覆盖之前的回调绑定,导致只有最后一次查询会触发回调,且无法区分结果对应哪个排行榜。下面给两种实用的解决方法:
方法一:用字典关联查询句柄与排行榜名称(适合动态数量的排行榜)
这种方法通过字典记录每个查询请求对应的排行榜名称,回调时根据查询句柄匹配名称,再分配到对应的句柄变量。
- 定义存储变量和回调实例:
// 存储待处理的查询请求:键是查询句柄,值是排行榜名称 private Dictionary<SteamAPICall_t, string> _pendingLeaderboardQueries = new Dictionary<SteamAPICall_t, string>(); // 通用的排行榜查询回调实例 private CallResult<LeaderboardFindResult_t> _leaderboardFindCallResult; // 多排行榜句柄 private SteamLeaderboard_t m_Leaderboard_one; private SteamLeaderboard_t m_Leaderboard_two;
- 初始化回调:
void Awake() { _leaderboardFindCallResult = CallResult<LeaderboardFindResult_t>.Create(OnLeaderboardFindResult); }
- 封装查询方法:
public void RequestLeaderboard(string leaderboardName) { SteamAPICall_t callHandle = SteamUserStats.FindLeaderboard(leaderboardName); // 记录当前查询的句柄和对应名称 _pendingLeaderboardQueries.Add(callHandle, leaderboardName); // 绑定回调 _leaderboardFindCallResult.Set(callHandle); }
- 处理回调(注意要添加
SteamAPICall_t参数):
void OnLeaderboardFindResult(LeaderboardFindResult_t pCallback, bool bIOFailure, SteamAPICall_t callHandle) { // 先从字典中取出当前查询的排行榜名称 if (!_pendingLeaderboardQueries.TryGetValue(callHandle, out string leaderboardName)) { Debug.LogWarning("Unknown leaderboard query callback"); return; } // 处理完后移除记录,避免内存泄漏 _pendingLeaderboardQueries.Remove(callHandle); if (bIOFailure) { Debug.LogError($"IO Failed when finding leaderboard: {leaderboardName}"); return; } if (pCallback.m_bLeaderboardFound == 0) { Debug.LogError($"Leaderboard not found: {leaderboardName}"); return; } // 根据名称分配到对应的句柄 switch (leaderboardName) { case "YourLeaderboardOneName": m_Leaderboard_one = pCallback.m_hSteamLeaderboard; Debug.Log($"Loaded leaderboard: {leaderboardName}"); break; case "YourLeaderboardTwoName": m_Leaderboard_two = pCallback.m_hSteamLeaderboard; Debug.Log($"Loaded leaderboard: {leaderboardName}"); break; // 可扩展更多排行榜 } }
方法二:为每个排行榜创建独立回调实例(适合固定数量的排行榜)
如果你的排行榜数量固定,直接给每个排行榜分配独立的CallResult和回调方法,逻辑更直观。
- 定义独立的回调和句柄:
private CallResult<LeaderboardFindResult_t> _findLeaderboardOneResult; private CallResult<LeaderboardFindResult_t> _findLeaderboardTwoResult; private SteamLeaderboard_t m_Leaderboard_one; private SteamLeaderboard_t m_Leaderboard_two;
- 初始化各回调:
void Awake() { _findLeaderboardOneResult = CallResult<LeaderboardFindResult_t>.Create(OnLeaderboardOneFound); _findLeaderboardTwoResult = CallResult<LeaderboardFindResult_t>.Create(OnLeaderboardTwoFound); }
- 发起查询:
public void LoadAllLeaderboards() { // 查询第一个排行榜 SteamAPICall_t handleOne = SteamUserStats.FindLeaderboard("YourLeaderboardOneName"); _findLeaderboardOneResult.Set(handleOne); // 查询第二个排行榜 SteamAPICall_t handleTwo = SteamUserStats.FindLeaderboard("YourLeaderboardTwoName"); _findLeaderboardTwoResult.Set(handleTwo); }
- 各自的回调处理:
void OnLeaderboardOneFound(LeaderboardFindResult_t callback, bool ioFail) { if (!ioFail && callback.m_bLeaderboardFound != 0) { m_Leaderboard_one = callback.m_hSteamLeaderboard; Debug.Log("Leaderboard One loaded successfully"); } } void OnLeaderboardTwoFound(LeaderboardFindResult_t callback, bool ioFail) { if (!ioFail && callback.m_bLeaderboardFound != 0) { m_Leaderboard_two = callback.m_hSteamLeaderboard; Debug.Log("Leaderboard Two loaded successfully"); } }
为什么之前的方法失效?
你之前复用同一个OnLeaderboardFindResultCallResult实例,每次调用Set(handle)都会替换掉之前绑定的查询句柄,导致只有最后一次的查询请求会触发回调,前面的请求回调被覆盖,自然无法区分结果。
内容的提问来源于stack exchange,提问作者MatterGoal
相关产品推荐
相关产品推荐

