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

# ソース コードとベスト プラクティス - Winter Starfall

> Winter Starfall のソース コードをダウンロードするためのチュートリアルと、ログインおよび購入シナリオのベスト プラクティス。

# Winter Starfall のソース コードとシナリオ

このチュートリアルには、Winter Starfall のソース コードをダウンロードして実行する手順と、ログインおよび購入シナリオのベスト プラクティスを示すコード サンプルの解説が含まれています。

## ソース コードのダウンロード

### 前提条件

* Node JS をインストールする
* Visual Studio Code をインストールする

### ローカル開発のセットアップ

1. [GitHub](https://github.com/PlayFab/winter-starfall) からソース コードをダウンロードします。
2. VS Code で `/website` フォルダーを開き、推奨されるすべての拡張機能をインストールします。
3. `/website` ディレクトリで npm install を実行し、すべての依存関係をインストールします。
4. `npm run dev` を使用してサイトを起動します。表示されるリンクを選択してサイトを確認します。

### Azure 資格情報

AZURE\_CREDENTIALS シークレットを更新するには、Azure Portal のシェルで次のコマンドを実行します。

`az ad sp create-for-rbac --name "VanguardOutrider2" --role contributor --scopes /subscriptions/YOUR_SUBSCRIPTION_ID/resourceGroups/YOUR_RESOURCE_GROUP_NAME --json-auth`

## ログイン フロー

Winter Starfall のプレイヤー認証フローには 2 つのステップがあります。ログイン呼び出しと、サービスからプレイヤー情報を取得してストーリーの正しい位置にロードするために使用されるログイン後関数です。

### プレイヤー認証

ログイン部分については、[use-login.tsx](https://github.com/PlayFab/winter-starfall/blob/main/website/src/hooks/use-login.ts) ファイルで、プレイヤーが利用できる複数の認証方法を処理する TypeScript ラッパー関数が定義されています。

144 ～ 169 行目では、電子メール アドレスによるログインのコールバック関数が定義されており、ログインに成功した場合にログイン後関数を呼び出します。

```typescript theme={null}
const onLogin = useCallback(() => {
    setIsLoading(true);
    setLoginMethodInProgress("email");

    dispatch(siteSlice.actions.loginSteps(loginEventCount));

    ClientLoginWithEmailAddress({ Email: data.email, Password: data.password })
        .then(result => {
            dispatch(siteSlice.actions.login(result));
            dispatch(siteSlice.actions.loginStepsAdvance());
            // Track logins from returning users
            trackEvent({ name: "Returning User", properties: {} });
        })
        .then(() => {
            return postLoginFunctions();
        })
        .then(() => {
            setIsLoading(false);
            navigate(routes.Explore());
        })
        .catch(problem => {
            dispatch(siteSlice.actions.loginStepsReset());
            onError(problem);
        })
        .finally(() => dispatch(siteSlice.actions.loginStepsReset()));
}, [ClientLoginWithEmailAddress, data.email, data.password, dispatch, navigate, onError, postLoginFunctions]);
```

このゲームは、プレイヤー アカウントが失われないよう、電子メール、Google、Facebook という 3 つの回復可能なプレイヤー認証方法を提供しています。詳細については、[ログインのベスト プラクティス](/services/playfab/identity/player-identity/login/login-basics-best-practices)を参照してください。

### ログイン後: プレイヤー データの取得

セキュリティ トークンが取得されると、それを使用してログイン後関数を実行し、保存されたゲーム状態を取得します。

340 ～ 378 行目では **postLoginFunctions** が定義されており、さまざまな Economy と PlayFab Services の API を呼び出して、プレイヤーに応じた正しいストーリーの位置、インベントリ アイテム、通貨などをロードします。

```typescript theme={null}
return new Promise<void>((resolve, reject) => {
    ClientGetTitleData({ Keys: TITLE_DATA_KEYS_ALL })
        .then(result => {
            dispatch(siteSlice.actions.titleData(result));
            dispatch(siteSlice.actions.loginStepsAdvance());
            loadScripts();
        })
        .then(() =>
            EconomySearchItems({
                Count: SEARCH_ITEMS_MAX_COUNT,
                Filter: "type eq 'currency' or type eq 'catalogItem'",
            })
        )
        .then(result => {
            dispatch(siteSlice.actions.catalog(result.Items));
            dispatch(siteSlice.actions.loginStepsAdvance());
        })
        .then(() => EconomyGetInventoryItems({ Count: SEARCH_ITEMS_MAX_COUNT }))
        .then(result => {
            dispatch(siteSlice.actions.inventory(result.Items));
            dispatch(siteSlice.actions.loginStepsAdvance());
        })
        .then(() => ClientGetUserData({ Keys: USER_DATA_KEYS_PLAYER_ALL }))
        .then(result => {
            dispatch(siteSlice.actions.userDataPlayer(result));
            dispatch(siteSlice.actions.loginStepsAdvance());
        })
        .then(() => ClientGetUserReadOnlyData({ Keys: USER_DATA_KEYS_READONLY_ALL }))
        .then(result => {
            dispatch(siteSlice.actions.userDataReadOnly(result));
            dispatch(siteSlice.actions.loginStepsAdvance());
        })
        .then(() => {
            resolve();
        })
        .catch(problem => {
            dispatch(siteSlice.actions.loginStepsReset());
            reject(problem);
        });
});
```

* まず `ClientGetTitleData` がすべての API 呼び出しに必要なシークレット キーを取得します。
* 次に `EconomySearchItems` がカタログから通貨とアイテム タイプを検索します。
* その結果を `EconomyGetInventoryItems` の入力として使用し、プレイヤーのインベントリ アイテムを返します。
* そして `ClientGetUserData` が、プレイヤー データの一部としてストーリーの位置を保存している値を取得します。

## 購入フロー

ゲームの特定のポイントで、プレイヤーはストアからインベントリ アイテムを購入したり売却したりできます。購入フローは別のラッパー関数として実装されています。[use-store.tx](https://github.com/PlayFab/winter-starfall/blob/main/website/src/hooks/use-store.ts) ファイルの 40 ～ 69 行目では、特定の場所でプレイヤーが遭遇する正しいストアを表示し、カタログを検索して販売中のアイテムを設定します。

```typescript theme={null}
export function useEconomyStoreSingle(storeName: string): IEconomyStoreSingleResults {
    const dispatch = useDispatch();
    const store = useSelector((state: AppState) => state.site.stores).find(store =>
        store.AlternateIds?.find(friendlyId => friendlyId.Type === FRIENDLYID && friendlyId.Value === storeName)
    );
    const { isLoading, error, setError, EconomyGetItem } = usePlayFab();

    useEffect(() => {
        if (!is.null(store) || isStoreLoading) {
            return;
        }

        isStoreLoading = true;

        EconomyGetItem({
            AlternateId: { Type: FRIENDLYID, Value: storeName },
        })
            .then(results => {
                dispatch(siteSlice.actions.storeAdd(results.Item as PlayFabEconomyModels.CatalogItem));
            })
            .catch(setError)
            .finally(() => {
                isStoreLoading = false;
            });
    }, [EconomyGetItem, dispatch, setError, store, storeName]);

    return {
        error,
        isLoading,
        store,
    };
}
```

`EconomyGetItem` は [use-playfab.tsx](https://github.com/PlayFab/winter-starfall/blob/main/website/src/hooks/use-playfab.ts) の 423 ～ 446 行目で定義されており、その中で PlayFab Economy API の `GetItems` を使用してカタログを検索し、アイテムを返します。

```typescript theme={null}
const EconomyGetItems = useCallback(
        (request: PlayFabEconomyModels.GetItemsRequest): Promise<PlayFabEconomyModels.GetItemsResponse> => {
            const date = startRequest("EconomyApi", "GetItems", request);

            return new Promise((resolve, reject) => {
                PlayFab.EconomyApi.GetItems(request, (result, problem) => {
                    endRequest(date, problem, result);

                    if (!is.null(problem)) {
                        return reject(problem);
                    }

                    if (result.code !== 200) {
                        return reject(formatPlayFabNon200Error(result));
                    }

                    return resolve(result.data);
                }).catch(reason => {
                    catchRequest(reject, reason);
                });
            });
        },
        [catchRequest, endRequest, startRequest]
    );
```

購入が行われると、`PurchaseInventoryItems` API への呼び出しが行われます。これは [use-playfab.tsx](https://github.com/PlayFab/winter-starfall/blob/main/website/src/hooks/use-playfab.ts) の 540 ～ 565 行目で定義されています。

### アイテムの売却

売却フローは、Azure Functions で動作する CloudScript を使用して Economy システムの機能を拡張する例です。

[SellItem.cs](https://github.com/PlayFab/winter-starfall/blob/main/azure-functions/SellItem.cs) では、アイテムを売却する際に実行される CloudScript 関数を定義しています。

49 ～ 61 行目では、PlayFab の `GetTitleData API` を使用してストア乗数を取得し、売却価格を計算しています。

```csharp theme={null}
 // Get your sell multiplier
var titleData = await PlayFabFunctions.GetTitleDataAsync(player, new List<string> { TitleDataKeys.Multipliers }, log);
var sellMultiplier = JsonConvert.DeserializeObject<Multipliers>(titleData[TitleDataKeys.Multipliers])?.sell ?? 1;
```

CloudScript 関数は、[use-store.ts](https://github.com/PlayFab/winter-starfall/blob/main/website/src/hooks/use-store.ts) の 161 ～ 187 行目で呼び出されます。

```typescript theme={null}
export function useEconomyStoreSell(): IEconomyStoreSellItemResults {
    const { isLoading, error, setError, CloudScriptExecuteFunction, EconomyGetInventoryItems } = usePlayFab();
    const dispatch = useDispatch();

    const onSell = useCallback(
        (itemId: string, amount: number) => {
            return new Promise<void>((resolve, reject) => {
                CloudScriptExecuteFunction({
                    FunctionName: "SellItem",
                    FunctionParameter: {
                        ItemId: itemId,
                        Amount: amount,
                    },
                })
                    .then(() => EconomyGetInventoryItems({ Count: SEARCH_ITEMS_MAX_COUNT }))
                    .then(data => {
                        dispatch(siteSlice.actions.inventory(data.Items));
                        resolve();
                    })
                    .catch(issue => {
                        setError(issue);
                        reject(issue);
                    });
            });
        },
        [CloudScriptExecuteFunction, EconomyGetInventoryItems, dispatch, setError]
    );
```

<Note>
  Winter Starfall をローカルで実行するには、CloudScript 関数をサポートするための Azure アカウントが必要です。[無料の Azure アカウントに登録](https://azure.microsoft.com/pricing/purchase-options/azure-account?msockid=1dec68fa155462cb2baa7ca6147963d7)し、上記の手順に従って Azure 資格情報を正しくリセットしてください。
</Note>

## 関連項目

* ログイン フロー
  * [プレイヤー ログインのドキュメント](/services/playfab/identity/player-identity/login)
* 購入フロー
  * [Economy V2 のドキュメント](/services/playfab/economy-monetization/economy-v2/overview)
  * Economy V2 についてさらに学ぶための次のステップとして、[クラフト ゲームのチュートリアル](/services/playfab/economy-monetization/economy-v2/tutorials/craftingGame/game-context)を試してみることもお勧めします。このチュートリアルは、ストアとインベントリの機能を使用してサンプル ゲームを構築することに重点を置いています。


## Related topics

- [ログインの基本とベスト プラクティス](/ja-jp/services/playfab/identity/player-identity/login/login-basics-best-practices.md)
- [XR-115 プレイ中のユーザーまたはコントローラーの追加と削除](/ja-jp/publishing/certification/xr/xr-115.md)
- [Winter Starfall PlayFab デモ ゲームの概要](/ja-jp/services/playfab/demo-game/overview.md)
- [SDK エラー処理のベスト プラクティス](/ja-jp/services/playfab/live-service-management/service-gateway/automation/cloudscript/sdk-error-handling-best-practices.md)
- [Insights のベスト プラクティス](/ja-jp/services/playfab/data-analytics/legacy/insights/best-practices.md)
