> ## 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.

# 使用玩家發行者資料獎勵多遊戲遊玩

> 使用 PlayFab 玩家發行者資料和 CloudScript 追蹤跨遊戲登入，並為遊玩多個遊戲的玩家授與虛擬貨幣獎勵。

獎勵通常涉及玩家資料以外的*其他*系統，因此為了簡單起見，此範例示範授與虛擬貨幣。

## 需求

* [PlayFab 開發人員帳戶](https://developer.playfab.com)。
* 玩家必須使用相同的認證登入*兩個*遊戲。一種做法是使用**可復原的認證**，如我們的[登入基本概念和最佳做法](/zh-TW/services/playfab/identity/player-identity/login/login-basics-best-practices)教學課程中所述。若要將**可復原**的登入新增至匿名帳戶，請參閱我們的[帳戶連結](/zh-TW/services/playfab/identity/player-identity/login/quickstart)教學課程。
* 此範例需要具備 [CloudScript](/zh-TW/services/playfab/live-service-management/service-gateway/automation/cloudscript/writing-custom-cloudscript) 的實務知識：
  * 我們的範例示範基本的資料安全性，以避免玩家作弊。如果遊戲使用自訂遊戲伺服器，同樣也可以在其上使用伺服器 API。
* 透過 PlayFab 觸發的獎勵需要使用適當的 PlayFab 功能。PlayFab 獎勵的形式可以是[**虛擬貨幣**](/zh-TW/services/playfab/economy-monetization/economy-v2/tutorials/currencies)、[**物品欄物品**](/zh-TW/services/playfab/player-progression/player-data/player-inventory)、[**自訂玩家資料**](/zh-TW/services/playfab/player-progression/player-data/quickstart)、[**統計資料**](/zh-TW/services/playfab/community/leaderboards/tournaments-leaderboards/using-player-statistics)等。在 PlayFab 系統之外發放獎勵是進階主題，本教學課程不涵蓋。

我們也建議開發人員對從 CloudScript 發出的所有伺服器 API 呼叫進行良好的錯誤處理。

## 每個遊戲向發行者資料回報登入

每個遊戲都需要回報發生了登入。為了簡單起見，我們的範例對於每個遊戲，只會針對遊玩過的每個其他發行者遊戲提供*一次*獎勵。

您可以使用計數器、時間戳記或其他機制擴充此概念，以提供漸進式或連續的獎勵。

您工作室中的*每個*遊戲都需要具備下列 CloudScript。

```javascript theme={null}
// CloudScript/Javascript

var PUBLISHER_USED_TITLES_KEY = "playedTitleIds";
handlers.TrackTitleUsage = function () {
    // Get the User Publisher Data for this player, and convert it into our expected format
    var getRequest = { Keys: [PUBLISHER_USED_TITLES_KEY], PlayFabId: currentPlayerId };
    var getResult = server.GetUserPublisherInternalData(getRequest);
    var playedTitlesList = JSON.parse(getResult.Data[PUBLISHER_USED_TITLES_KEY].Value); // format is arbitrary, but this example assumes Array<string>
    if (!playedTitlesList)
        playedTitlesList = [];
    // Check if we've played this title already
    var alreadyPlayed = false;
    for (var i = 0; i < playedTitlesList.length; i++)
        alreadyPlayed = alreadyPlayed || playedTitlesList[i] === script.titleId;
    if (alreadyPlayed)
        return; // Nothing to do
    // Update the list of played titles, and re-save
    playedTitlesList.push(script.titleId);
    var setRequest = { PlayFabId: currentPlayerId, Data: { PUBLISHER_USED_TITLES_KEY: JSON.stringify(playedTitlesList) } };
    server.UpdateUserPublisherInternalData(setRequest);
}
```

具體而言，此範例示範如何使用：

* server.[GetUserPublisherInternalData](xref:titleid.playfabapi.com.server.playerdatamanagement.getuserpublisherinternaldata)
* server.[UpdateUserPublisherInternalData](xref:titleid.playfabapi.com.server.playerdatamanagement.updateuserpublisherinternaldata)。

## 每個遊戲檢查可兌換的獎勵

在追蹤遊玩過哪些遊戲之後，您需要追蹤並授與獎勵。此 CloudScript 函式會根據遊玩過的其他遊戲，檢查並授與可用的獎勵。

```javascript theme={null}
// CloudScript/Javascript

var PUBLISHER_REDEEMED_TITLES_KEY = "redeemedTitleIds";
var MY_CROSS_TITLE_REWARDS = { "AU": 10 };
handlers.CheckCrossTitleRewards = function () {
    // Get the publisher data concerning cross-title rewards for this player
    var getRequest = { Keys: [PUBLISHER_USED_TITLES_KEY, PUBLISHER_REDEEMED_TITLES_KEY], PlayFabId: currentPlayerId };
    var getResult = server.GetUserPublisherInternalData(getRequest);
    var redeemedTitleRewards = JSON.parse(getResult.Data[PUBLISHER_REDEEMED_TITLES_KEY].Value); // format is arbitrary, but this example assumes { [key: string]: Array<string> }
    if (!redeemedTitleRewards)
        redeemedTitleRewards = {};
    var playedTitlesList = JSON.parse(getResult.Data[PUBLISHER_USED_TITLES_KEY].Value); // format is arbitrary, but this example assumes Array<string>
    if (!playedTitlesList)
        playedTitlesList = [];

    // Determine which titles are un-redeemed
    var unredeemedTitleIds = [];
    for (var i = 0; i < playedTitlesList.length; i++) {
        if (!redeemedTitleRewards.hasOwnProperty(playedTitlesList[i]) && playedTitlesList[i] !== script.titleId)
            unredeemedTitleIds.push(playedTitlesList[i]);
    }
    if (unredeemedTitleIds.length === 0)
        return null; // Nothing to redeem

    // Give the cross title rewards
    var multiplier = unredeemedTitleIds.length;
    var actualRewards = {}; // MY_CROSS_TITLE_REWARDS is a global constant, so don't modify it or you'll mess up future calls
    // Please note that the number of API calls that may be made from CloudScript, as well as the total available processing time is limited,
    // and so the number of rewards should be as small as possible (only one VC, in this case)
    for (var eachKey in MY_CROSS_TITLE_REWARDS) {
        actualRewards[eachKey] = MY_CROSS_TITLE_REWARDS[eachKey] * multiplier;
        server.AddUserVirtualCurrency({ PlayFabId: currentPlayerId, VirtualCurrency: eachKey, Amount: MY_CROSS_TITLE_REWARDS[eachKey] }); // Can only add 1 VC at a time
    }

    // Save the Publisher data indicating rewards are claimed
    redeemedTitleRewards[script.titleId] = playedTitlesList;
    var setRequest = { PlayFabId: currentPlayerId, Data: { PUBLISHER_REDEEMED_TITLES_KEY: JSON.stringify(redeemedTitleRewards) } };
    server.UpdateUserPublisherInternalData(setRequest);

    // Tell the client the reward
    return actualRewards;
};
```

<Note>
  此特定範例示範如何使用 server.[GetUserPublisherInternalData](xref:titleid.playfabapi.com.server.playerdatamanagement.getuserpublisherinternaldata) (要求多個索引鍵)、server.[UpdateUserPublisherInternalData](xref:titleid.playfabapi.com.server.playerdatamanagement.updateuserpublisherinternaldata) 和 server.[AddUserVirtualCurrency](xref:titleid.playfabapi.com.server.playeritemmanagement.adduservirtualcurrency)。
</Note>

程式碼區塊代表下列步驟：

* 從 PlayFab 擷取資料，並將其剖析為本機資料結構 (呼叫 [GetUserPublisherInternalData](xref:titleid.playfabapi.com.server.playerdatamanagement.getuserpublisherinternaldata))。
* 檢查資料並搜尋尚未獎勵的遊戲識別碼。
* 授與獎勵 (呼叫 [AddUserVirtualCurrency](xref:titleid.playfabapi.com.server.playeritemmanagement.adduservirtualcurrency))。
* 更新已領取的獎勵 (呼叫 [UpdateUserPublisherInternalData](xref:titleid.playfabapi.com.server.playerdatamanagement.updateuserpublisherinternaldata))。
* 讓用戶端可以使用獎勵的數量 (透過 CloudScript 的 return 陳述式)。

## 結論

玩家發行者資料和玩家資料在結構上完全相同。

玩家資料應該是*遊戲特定的*，而玩家發行者資料*只*應包含與您所有遊戲相關的資訊。

## 另請參閱

[簡單的遊戲內交叉推廣](https://github.com/PlayFab/PlayFab-Samples/tree/master/Recipes/SimpleCrossPromotion)：獎勵參與您多個遊戲的玩家。


## Related topics

- [玩家資料](/zh-TW/services/playfab/player-progression/player-data/index.md)
- [使用發行者資料](/zh-TW/services/playfab/live-service-management/game-configuration/titledata/using-publisher-data.md)
- [遊戲資料快速入門](/zh-TW/services/playfab/live-service-management/game-configuration/titledata/quickstart.md)
- [取得使用者發行者資料](/zh-TW/services/playfab/api-references/rest/admin/player-data-management/get-user-publisher-data.md)
- [遊戲資料](/zh-TW/services/playfab/live-service-management/game-configuration/titledata/index.md)
