> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 排行榜

> 使用以事件為基礎的統計資料與 Partner Center 統計資料規則，在 XBOX GDK 上重建 Steam 排行榜，並提供比較兩種排行榜 API 的程式碼範例。

XBOX services 排行榜衍生自使用者統計資料，並透過查詢建立。這與 Steam 上的排行榜不同，Steam 排行榜是由上傳至 API 的「分數」所驅動。與成就類似，XBOX Game Development Kit (GDK) 有兩種統計資料 API：以事件為基礎與由遊戲管理。與成就不同的是，我們建議您使用以事件為基礎的統計資料和排行榜，而不是由遊戲管理的方式。本主題著重於該 API。如需這兩種 API 差異的詳細資訊，請參閱[以事件為基礎與由遊戲管理的統計資料](/zh-TW/services/xbox-services/player-data/stats-leaderboards/index)。

兩個平台都在其入口網站上定義排行榜。不同之處在於，XBOX services 要求您先在 Partner Center 上定義統計資料規則，然後根據該規則所驅動的統計資料建立排行榜。另一方面，Steam 並未區分兩者：您可以在其入口網站中或以程式設計方式建立排行榜，然後直接將使用者分數上傳至該排行榜。

為了說明這些 API 與 Steam Leaderboard API 相比各自的使用方式，我們提供了程式碼範例，示範如何在 Steam SDK 和以事件為基礎的 XBOX Game Development Kit (GDK) 統計資料平台上，建立最遠移動距離的排行榜 (此範例取自 Steamworks API 文件)。下列各節將逐步說明其邏輯。

## 在入口網站中建立統計資料/排行榜

### Steamworks

在 Steamworks 管理入口網站上，前往 **Stats & Achievements** > **Leaderboards**。依照下列螢幕擷取畫面 (取自 Steamworks 文件) 所示填寫表單。

<img src="https://mintcdn.com/microsoft-4404708b/5IpvKlT-jmAaVkeY/images/nda/steam-porting-guide/steam-portal-add-leaderboard.png?fit=max&auto=format&n=5IpvKlT-jmAaVkeY&q=85&s=e8a3f4a76f8a9bdc60689571bf5a9dbb" alt="用來在 Steamworks 管理入口網站中建立排行榜之表單的螢幕擷取畫面" width="806" height="190" data-path="images/nda/steam-porting-guide/steam-portal-add-leaderboard.png" />

### XBOX Game Development Kit (GDK) (以事件為基礎)

在 Partner Center 上，前往您的遊戲，然後選取 **XBOX services** > **Gameplay settings**。在右側窗格的導覽列上，選取 **Player Stats** > **Stat Rules**，並以 **Show** 的方式新增統計資料規則，依據您統計資料的需求進行設定。由於我們的統計資料更新會包含玩家 (使用者) 自上次更新以來移動距離的計算值，因此我們會指定一個測量欄位，讓服務從中取得此值。

<Note>
  無論您將用來更新事件的資料儲存在事件的 Measurements 或 Dimensions 欄位中，在功能上都沒有差異。這兩個欄位是為了搭配 Application Insights 使用而存在。如需詳細資訊，請參閱 \[適用於自訂事件和
</Note>

指標的 Application Insights API]\([https://learn.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics](https://learn.microsoft.com/en-us/azure/azure-monitor/app/api-custom-events-metrics))。

下列螢幕擷取畫面顯示用來在 Partner Center 中建立統計資料規則的表單。

<img src="https://mintcdn.com/microsoft-4404708b/5IpvKlT-jmAaVkeY/images/nda/steam-porting-guide/partner-center-stat-rule.png?fit=max&auto=format&n=5IpvKlT-jmAaVkeY&q=85&s=08b05f51f44f9f912854674ea3c189ae" alt="用來在 Partner Center 中建立統計資料規則之表單的螢幕擷取畫面" width="1196" height="1046" data-path="images/nda/steam-porting-guide/partner-center-stat-rule.png" />

儲存之後，在右側窗格的頂端列上選取 **Leaderboard**，並建立由您剛才建立的統計資料所驅動的新排行榜，如下列螢幕擷取畫面所示。

<img src="https://mintcdn.com/microsoft-4404708b/5IpvKlT-jmAaVkeY/images/nda/steam-porting-guide/partner-center-leaderboard.png?fit=max&auto=format&n=5IpvKlT-jmAaVkeY&q=85&s=5ffd10e8fdb53ed640fcb59ef31e323a" alt="用來在 Partner Center 中建立排行榜之表單的螢幕擷取畫面" width="1048" height="654" data-path="images/nda/steam-porting-guide/partner-center-leaderboard.png" />

## 上傳分數

### Steamworks

在 Steamworks 上，您需要計算移動英尺數的新總值，並使用 `ISteamUserStats::UploaderLeaderboardScore` 方法將其傳送至 API。

```cpp theme={null}
int32 newFeetTraveled; // Calculate this however you want.
const int32* scoreDetails = {}; // Extra values pertaining to the score.
SteamLeaderboard_t leaderboard; // Handle for the leaderboard to upload the score to...
SteamAPICall_t result = UploadLeaderboardScore( leaderboard, ISteamUserStats::k_ELeaderboardUploadScoreMethodForceUpdate, 100, scoreDetails, int 0);
STEAM_CALLBACK(MyGameClass, OnLeaderboardScoreUploaded, LeaderboardScoreUploaded_t);
// Handle errors in the OnLeaderboardScoreUploaded callback function.
```

### XBOX Game Development Kit (GDK) (以事件為基礎)

使用 XBOX Game Development Kit (GDK) 中以事件為基礎的統計資料時，您只需將移動英尺數的差值傳遞給 [`XblEventsWriteInGameEvent`](/zh-TW/reference/live/xsapi-c/events_c/events_c_members)，因為我們已指定在收到事件時要遞增此統計資料，並已指定在測量 JSON 字串中何處可找到此 `diff` 值，如下所示。

```cpp theme={null}
// Assume that this holds the feet that the user has traveled since the last update.
int diffFeetTraveled; 
std::stringstream ss;
ss << "{ \"feet\": " << diffFeetTraveled << " }";
std::string measurements = ss.str();
HRESULT hr = XblEventsWriteInGameEvent(
    m_xboxLiveContext,
    "FeetTraveled",
    "",
    measurements.c_str()
);
```

如需詳細資訊，請參閱[寫入事件以驅動以事件為基礎的統計資料](/zh-TW/services/xbox-services/player-data/stats-leaderboards/index)。

## 取得全域排行榜

使用 Steamworks SDK 時，可以呼叫 `ISteamUserStats::GetLeaderboardEntries` 來擷取全域排行榜，然後在 `callback` 函式中呼叫 `ISteamUserStats::GetDownloadedLeaderboardEntry`，以取得排行榜的每個項目或「列」。

### Steamworks

```cpp theme={null}
class MyGameClass
{
    void OnFindLeaderboardCompleted(LeaderboardFindResult_t *callback);
    SteamAPICall_t m_getLoaderboardCall;
    SteamAPICall_t m_getEntriesCall;
};

m_getLoaderboardCall = SteamUserStats()->FindLeaderboard(leaderboardName);
STEAM_CALLBACK(MyGameClass, OnFindLeaderboardCompleted, LeaderboardFindResult_t);

// ...

void MyGameClass::OnFindLeaderboardCompleted(LeaderboardFindResult_t *callback)
{
    if (callback->bLeaderboardFound)
    {
        auto handle = callback->m_hSteamLeaderboard;
        const char *leaderboardName = SteamUserStats()->GetLeaderboardName(handle);
        m_getEntriesCall = SteamUserStats()->GetLeaderboardEntries(handle, ELeaderboardDataRequest::k_ELeaderboardDataRequestGlobal, 0, 100);
        STEAM_CALLBACK(MyGameClass, OnLeaderboardScoresDownloaded, LeaderboardScoresDownloaded_t);
    }
    else
    {
        // Leaderboard wasn't found.
    }

void MyGameClass::OnLeaderboardScoresDownloaded(LeaderboardScoresDownloaded_t *callback)
{
    int numScores = callback->m_cEntryCount;
    for (int i = 0; i < numScores; i++)
    {
        LeaderboardEntry_t entry;
        bool result = SteamUserStats()->GetDownloadedLeaderboardEntry(callback->m_hSteamLeaderboardEntries, i, &entry, nullptr, 0);
        if (!result)
        {
            // Handle error.
        }
        CSteamID userId = entry.m_steamIDUser;
        int32 rank = entry.m_nglobalRank;
        int32 score = entry.m_nScore;
        // Do something with the data. 
    }
}
```

### XBOX Game Development Kit (GDK) (以事件為基礎)

XBOX Game Development Kit (GDK) API 遵循類似的模式。建立一個查詢，指定您想要的排行榜、其涵蓋範圍、排序方式、應包含哪些額外欄位 (如果有的話) 等。使用您的查詢呼叫 [`XblLeaderboardGetLeaderboardAsync`](/zh-TW/reference/live/xsapi-c/leaderboard_c/leaderboard_c_members) 之後，您可以使用 [`XblLeaderboardGetLeaderboardResultSize`](/zh-TW/reference/live/xsapi-c/leaderboard_c/leaderboard_c_members) 和 [`XblLeaderboardGetLeaderboardResult`](/zh-TW/reference/live/xsapi-c/leaderboard_c/leaderboard_c_members) 將結果放入您指定的緩衝區，並逐一查看結果，如下列程式碼範例所示。

```cpp theme={null}
auto asyncBlock = std::make_unique<XAsyncBlock>();
asyncBlock->queue = m_taskQueue;
asyncBlock->context = nullptr;
asyncBlock->callback = [](XAsyncBlock* asyncBlock)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*
    size_t resultSize;
    std::vector<uint8_t> leaderboardBuffer;
    HRESULT hr = XblLeaderboardGetLeaderboardResultSize(asyncBlock, &resultSize);

    if (SUCCEEDED(hr))
    {
        leaderboardBuffer.resize(resultSize);
        XblLeaderboardResult* leaderboard{};

        hr = XblLeaderboardGetLeaderboardResult(asyncBlock, resultSize, leaderboardBuffer.data(), &leaderboard, nullptr);

        if (SUCCEEDED(hr))
        {
            // Use XblLeaderboardResult in result.
            for (int row = 0; row < leaderboard->rowsCount; row++)
            {
                uint64_t xuid = leaderboard->rows[row].xboxUserId;
                uint32_t rank = leaderboard->rows[row].rank;
                const char** values = leaderboard->rows[row].columnValues;
                // Do something with the data.
            }
        }
    }
};

XblLeaderboardQuery leaderboardQuery = {}; 
strcpy(&leaderboardQuery.scid[0], m_scid.c_str());
leaderboardQuery.leaderboardName = leaderboardName.c_str(); 
leaderboardQuery.xboxUserId = 0;
leaderboardQuery.order = XblLeaderboardSortOrder::Descending;
leaderboardQuery.skipResultToRank = 0;
leaderboardQuery.maxItems = 100;
leaderboardQuery.statName = "MyStatName";
leaderboardQuery.socialGroup = XblLeaderboardQueryType::None;
// See the link as follows for more options in XblLeaderboardQuery.

HRESULT hr = XblLeaderboardGetLeaderboardAsync(
    xboxLiveContext,
    leaderboardQuery,
    asyncBlock.get());
if (SUCCEEDED(hr))
{
    // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
    // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
    asyncBlock.release();
}
```

如需詳細資訊，請參閱下列內容：

* [以事件為基礎之排行榜的範例程式碼](/zh-TW/services/xbox-services/player-data/stats-leaderboards/index)
* [XblLeaderboardQuery](/zh-TW/reference/live/xsapi-c/leaderboard_c/leaderboard_c_members)

## 取得社交排行榜

在 Steamworks 上，您可以使用 `ELeaderboardDataRequest::k_ELeaderboardDataRequestFriends` 列舉，將排行榜範圍限定為目前使用者的好友。

在 XBOX Game Development Kit (GDK) 中，這稱為\_社交排行榜\_。若要從 XBOXBOX services 取得社交排行榜，請在您的 [`XblLeaderboardQuery`](/zh-TW/reference/live/xsapi-c/leaderboard_c/leaderboard_c_members) 結構中，將 `xboxIUserId` 設為目前登入 XBOX services 之使用者的 XBOX 使用者識別碼 (XUID)、將 `leaderboardName` 設為 `nullptr`，並將 `socialGroup` 設為 `XblSocialGroupType::People` 或 `XblSocialGroupType::Favorites`。依照先前所示呼叫 `XblLeaderboardGetLeaderboardAsync`。

如需詳細資訊，請參閱 [XblSocialGroupType](/zh-TW/reference/live/xsapi-c/leaderboard_c/leaderboard_c_members)。

## 精選統計資料

除了用來產生類似 Steam 排行榜的一般使用者統計資料之外，XBOX services 還有一個稱為\_精選統計資料 (Featured Stats)\_ 的額外概念。精選統計資料會出現在 XBOX 生態系統中您遊戲的數個不同介面上，並且可以顯示使用者統計資料的值或已產生的排行榜。您最多可以為您的遊戲建立 20 個精選統計資料。

如需精選統計資料及如何新增的詳細資訊，請參閱[精選統計資料概觀](/zh-TW/services/xbox-services/player-data/stats-leaderboards/index)和[以事件為基礎之精選統計資料的入口網站設定](/zh-TW/services/xbox-services/player-data/stats-leaderboards/index)。

## 速率限制

寫入事件時，請小心避免過於頻繁地呼叫 XBOX Services API (XSAPI)，因為這可能會導致您的遊戲達到其速率限制。這可能會造成非預期的行為，並為您的使用者帶來不良體驗。請注意，這是 XBOX services 才有的考量，在 Steam 上並不是問題。在 Steam 上寫入統計資料值時，在您的遊戲明確同步之前，不會對伺服器發出 API 呼叫。

對於經常發生的事件，請嘗試批次處理 API 呼叫，在發生特定數量的事件後才觸發，或以特定時間間隔在伺服器上更新。

您可以使用 [XBOX Live Trace Analyzer (XblTraceAnalyzer.exe)](/zh-TW/tools/tools-services/live-trace-analyzer) 對您的 API 呼叫進行偵錯。

如需 XBOX services 速率限制的詳細資訊，請參閱[細部速率限制](/zh-TW/services/xbox-services/develop/best-practices/live-fine-grained-rate-limiting)。


## Related topics

- [錦標賽與排行榜](/zh-TW/services/playfab/community/leaderboards/tournaments-leaderboards/index.md)
- [排行榜配額](/zh-TW/services/playfab/community/leaderboards/quota-leaderboards.md)
- [排行榜 API 參考](/zh-TW/services/playfab/community/leaderboards/api-reference.md)
- [群組排行榜](/zh-TW/services/playfab/community/leaderboards/group-leaderboards.md)
- [排行榜計量](/zh-TW/services/playfab/pricing/meters/leaderboard-meters.md)
