---
title: 製品 API 使用例
slug: world-sdk-guide-ja/t4tu-api
docTags: 
createdAt: 2024-09-02T08:34:13.134Z
---

以下は、製品APIを使用して世界通貨と世界製品を管理する例です。

この例では、製品APIの基本的な理解を得て、サーバーとクライアント間でメッセージを送受信する実装を行うことができるため、世界通貨と製品の付与および控除を簡単にテストできます。

この例には、世界通貨と世界製品のクライアントスクリプトの説明が含まれており、その後、すべてのサーバーサイド処理を処理する統合サーバースクリプトが続き、以下の機能が含まれています：

- 世界通貨の付与
- 世界通貨の控除
- 通貨控除なしでの世界製品の付与
- 世界製品の控除

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-LVomjGT16SVteQlTOo7ug-20240904-102419.gif)



## 世界通貨の付与と控除

以下は、世界通貨の付与と控除を管理するための完全なクライアントコードと、その実装方法です。

### 通貨クライアントスクリプト

:::CodeblockTabs
CurrencyManagerSample

```typescript
import { Button, Text } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { LocalPlayer, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Room, RoomData } from 'ZEPETO.Multiplay';
import { ZepetoWorldMultiplay } from 'ZEPETO.World';
 
export default class CurrencyManagerSample extends ZepetoScriptBehaviour {
 
    public currencyId: string;
    public increaseQuantity: number;
    public decreaseQuantity: number;
    public increaseCurrencyBtn: Button;
    public decreaseCurrencyBtn: Button;
    public balanceText: Text;
    public multiplay: ZepetoWorldMultiplay;
 
    private _localPlayer: LocalPlayer;
 
    Start() {
 
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            this._localPlayer = ZepetoPlayers.instance.LocalPlayer;
            this.loadCurrencyBalance(this.currencyId);
        });
 
        // 通貨UIの更新のためのルーム参加イベントを処理します
        this.multiplay.RoomJoined += (room: Room) => {
            room.AddMessageHandler("SyncCurrencyInfo", (message: CurrencyMessage) => {
                const currentCurrencyId = message.currencyId;
                const currentQuantity = message.quantity;
                this.balanceUIUpdate(currentCurrencyId, currentQuantity);
            });
        };
 
        // 通貨を増やすためのボタンイベントリスナー : クレジットリクエスト
        this.increaseCurrencyBtn.onClick.AddListener(() => {
            const data = new RoomData();
            data.Add("currencyId", this.currencyId);
            data.Add("quantity", this.increaseQuantity);
            this.multiplay.Room?.Send("CreditCurrency", data.GetObject());
        })
 
        // 通貨を減らすためのボタンイベントリスナー : デビットリクエスト
        this.decreaseCurrencyBtn.onClick.AddListener(() => {
            const data = new RoomData();
            data.Add("currencyId", this.currencyId);
            data.Add("quantity", this.decreaseQuantity);
            this.multiplay.Room?.Send("DebitCurrency", data.GetObject());
        })
 
    }
 
    // 指定された通貨の現在の量をリクエストします
    private loadCurrencyBalance(currentCurrencyId: string) {
        this.multiplay.Room?.Send("LoadBalance", currentCurrencyId);
    }
 
    // 通貨の現在の量を反映するようにUIを更新します
    private balanceUIUpdate(currentCurrencyId: string, currentQuantity: number) {
        this.balanceText.text = currentQuantity.toString();
    }
 
}
 
// 通貨同期メッセージのインターフェース
interface CurrencyMessage {
    currencyId: string,
    quantity: number,
}
```
:::



### 通貨クライアントスクリプトの説明

- キャラクターがロードされると、サーバーにルームメッセージが送信され、既存の通貨の残高がロードされます。その後、サーバーから受信した残高情報に基づいてUIが更新されます。

```typescript
this.multiplay.Room?.Send("LoadBalance", currentCurrencyId);
```

- メッセージ交換を促進するために、`CurrencyMessage`インターフェースが定義されています。

```typescript
interface CurrencyMessage {
    currencyId: string,
    quantity: number,
}
```

- ユーザーが通貨を増減させると、彼らはサーバーにルームメッセージとしてリクエストを送信します。
  それには、どの通貨を増減させるか、そしてどのくらいの量を増減させるかのデータが含まれています。

```typescript
this.multiplay.Room?.Send("CreditCurrency", data.GetObject());
this.multiplay.Room?.Send("DebitCurrency", data.GetObject());
```

- サーバーは通貨の増減を処理し、最終的な残高情報をクライアントに送信します。クライアントはこの情報を受け取り、UIを更新します。

[完全なサーバースクリプトを見る](docId\:t4tuJD-mNGihOmX0DpyEQ)&#x20;


```typescript
this.multiplay.RoomJoined += (room: Room) => {
    room.AddMessageHandler("SyncCurrencyInfo", (message: CurrencyMessage) => {
        const currentCurrencyId = message.currencyId;
        const currentQuantity = message.quantity;
        this.updateBalanceUI(currentCurrencyId, currentQuantity);
    });
};
```



## 世界の製品の付与と控除

以下は、世界の製品の付与と控除を管理するための完全なクライアントコードと、その実装方法です。

### 製品クライアントスクリプト

:::CodeblockTabs
ProductManagerSample

```typescript
import { Button, Text } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { LocalPlayer, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Room, RoomData } from 'ZEPETO.Multiplay';
import { ZepetoWorldMultiplay } from 'ZEPETO.World';
import { InventoryRecord, InventoryService } from 'ZEPETO.Inventory';
import { WaitUntil } from 'UnityEngine';
 
export default class ProductManagerSample extends ZepetoScriptBehaviour {
 
    public productId: string;
    public productAddQuantity: number;
    public acquireItemBtn: Button;
    public useItemBtn: Button;
    public itemCountText: Text;
    public multiplay: ZepetoWorldMultiplay;
 
    private _localPlayer: LocalPlayer;
 
    Start() {
 
        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            this._localPlayer = ZepetoPlayers.instance.LocalPlayer;
            this.StartCoroutine(this.refreshProductUI());
        });
 
        // 製品UIの更新のためのルーム参加イベントを処理します
        this.multiplay.RoomJoined += (room: Room) => {
            room.AddMessageHandler("SyncProductInfo", (message: ProductMessage) => {
                this.StartCoroutine(this.refreshProductUI());
            });
        };
 
        // アイテム取得ボタンのイベントリスナー : 製品を追加
        this.acquireItemBtn.onClick.AddListener(() => {
            const data = new RoomData();
            data.Add("productId", this.productId);
            data.Add("quantity", this.productAddQuantity);
            this.multiplay.Room?.Send("AddProduct", data.GetObject());
        })
 
        // アイテム使用ボタンのイベントリスナー : 製品を使用
        this.useItemBtn.onClick.AddListener(() => {
            const data = new RoomData();
            data.Add("productId", this.productId);
            data.Add("quantity", 1);
            this.multiplay.Room?.Send("UseProduct", data.GetObject());
        })
 
    }
     
    private * refreshProductUI() {
        const request = InventoryService.GetAsync(this.productId);
        yield new WaitUntil(() => request.keepWaiting == false);
        // リクエストが成功した場合、製品UIを更新します
        if (request.responseData.isSuccess) {
            this.updateItemCountText(request.responseData.product);
        }
        else {
            console.log("製品アイテムの読み込みに失敗しました。");
        }
    }
 
    private updateItemCountText(item: InventoryRecord) {
        if (item != null) {
            this.itemCountText.text = item.quantity.toString();
        }
        else {
            this.itemCountText.text = "0";
        }
    }
 
}
 
// 製品メッセージのインターフェース。
interface ProductMessage {
    productId: string,
    productAction: ProductAction,
}
 
// 製品アクションタイプを定義するための列挙型。
export enum ProductAction {
    Use,
    Add,
}
```
:::



### 製品クライアントスクリプトの説明

- キャラクターがロードされるときは、`InventoryService`を使用して、[ZEPETO.Inventory](https://developer.zepeto.me/docs/product/namespaces/ZEPETO_Inventory/)を使用して、製品の初期インベントリをロードします。その後、UIを更新します。

```typescript
private * refreshProductUI() {
        const request = InventoryService.GetAsync(this.productId);
        yield new WaitUntil(() => request.keepWaiting == false);
        if (request.responseData.isSuccess) {
            this.updateItemCountText(request.responseData.product);
        }
        else {
            console.log("製品アイテムのロードに失敗しました。");
        }
    }
```

- メッセージを送受信するには、`ProductMessage`インターフェースを定義します。`ProductAction`列挙型を定義して、例の実装を行います。

```typescript
interface ProductMessage {
    productId: string,
    productAction: ProductAction,
}
 
export enum ProductAction {
    使用,
    追加,
}
```

- 製品を増減させるとき、そのデータをサーバーにルームメッセージとして送信します。
  どの製品をどれだけ増減させるかに関するデータが含まれています。

```typescript
this.multiplay.Room?.Send("AddProduct", data.GetObject());
this.multiplay.Room?.Send("UseProduct", data.GetObject());
```

- 製品の変更を処理した後、サーバーは最終的な在庫情報をクライアントに送信し、UIをそれに応じて更新します。

[完全なサーバースクリプトを表示](docId\:t4tuJD-mNGihOmX0DpyEQ)&#x20;

```typescript
this.multiplay.RoomJoined += (room: Room) => {
    room.AddMessageHandler("SyncProductInfo", (message: ProductMessage) => {
        this.StartCoroutine(this.refreshProductUI());
    });
};
```

:::hint{type="success"}
- 一般的に、ワールド製品は購入するために通貨が必要です。
- この場合、ガイドを参照して、**製品購入ボタン**を使って簡単に販売できます。[世界を収益化しよう！製品と通貨の設定](docId\:lQWw5DFMWkDVKcZNz07bs)&#x20;
:::



## サーバースクリプト

以下は、世界の通貨と製品を管理する完全なサーバーコードと、その実装方法です。

### 完全なサーバースクリプト

```typescript
import { Sandbox, SandboxOptions, SandboxPlayer } from "ZEPETO.Multiplay";
import { loadCurrency } from "ZEPETO.Multiplay.Currency";
import { loadInventory } from "ZEPETO.Multiplay.Inventory";

export default class extends Sandbox {

    async onCreate(options: SandboxOptions) {

        // 通貨
        //通貨の読み込みをリクエスト
        this.onMessage("LoadBalance", (client, message: string) => {
            this.loadBalance(client, message);
        });
        //クレジットの追加をリクエスト
        this.onMessage("CreditCurrency", (client, message: CurrencyMessage ) => {
            const currencyId = message.currencyId;
            const quantity = message.quantity;
            this.addCredit(client, currencyId, quantity);
        });
        //クレジットの引き落としをリクエスト
        this.onMessage("DebitCurrency", (client, message: CurrencyMessage ) => {
            const currencyId = message.currencyId;
            const quantity = message.quantity;
            this.onDebit(client, currencyId, quantity);
        });

        // 商品
        //アイテムの追加をリクエスト
        this.onMessage("AddProduct", (client, message: any) => {
            const productId = message.productId;
            const quantity = message.quantity;
            this.addProduct(client, productId, quantity);
        });
        //アイテムの使用をリクエスト
        this.onMessage("UseProduct", (client, message: any) => {
            const productId = message.productId;
            const quantity = message.quantity;
            this.useProduct(client, productId, quantity);
        });

    }

    async addCredit(client: SandboxPlayer, currencyId: string, quantity: number) {
        try {
            const currency = await loadCurrency(client.userId);
            await currency.credit(currencyId, quantity);
            this.loadBalance(client, currencyId);
        } catch (e) {
            console.error(`AddCredit Error: ${e}`);
        }
    }

    async onDebit(client: SandboxPlayer, currencyId: string, quantity: number) {
        try {
            const currency = await loadCurrency(client.userId);
            if (await currency.debit(currencyId, quantity) === true) {
                this.loadBalance(client, currencyId);
            } else {
                console.error("DebitCredit Error: 通貨が不足しています");
            }
        } catch (e) {
            console.error(`DebitCredit Error: ${e}`);
        }
    }

    async loadBalance(client: SandboxPlayer, currencyId: string) {
        try {
            const currency = await loadCurrency(client.userId);
            let balancesObject = await currency.getBalances();
            let balancesMap: Map<string, number> = new Map(Object.entries(balancesObject));
            const specificCurrencyID = currencyId;
            const specificBalance = balancesMap.get(specificCurrencyID) ?? 0;
            const currencySync: CurrencyMessage = {
                currencyId: specificCurrencyID,
                quantity: specificBalance
            }
            client.send("SyncCurrencyInfo", currencySync);
        } catch (e) {
            console.error(`loadBalance Error: ${e}`);
        }
    }

    async addProduct(client: SandboxPlayer, productId: string, quantity: number) {
        try {
            const inventory = await loadInventory(client.userId);
            await inventory.add(productId, quantity);
            const productMessage: ProductMessage = {
                productId: productId,
                productAction: ProductAction.Add
            }
            client.send("SyncProductInfo", productMessage);
        } catch (e) {
            console.error(`addProduct Error: ${e}`);
        }
    }

    async useProduct(client: SandboxPlayer, productId: string, quantity: number) {
        try {
            const inventory = await loadInventory(client.userId);
            await inventory.use(productId, quantity);
            const productMessage: ProductMessage = {
                productId: productId,
                productAction: ProductAction.Use
            }
            client.send("SyncProductInfo", productMessage);
        } catch (e) {
            console.error(`useProduct Error: ${e}`);
        }
    }

    onJoin(client: SandboxPlayer) {
        // 参加時のロジック
    }

    onTick(deltaTime: number): void {
        // タイックロジック
    }

    onLeave(client: SandboxPlayer, consented?: boolean) {
        // 退室時のロジック
    }

}

// 通貨メッセージのインターフェース
interface CurrencyMessage {
    currencyId: string,
    quantity: number,
}

// 商品メッセージのインターフェース。
interface ProductMessage {
    productId: string,
    productAction: ProductAction,
}

// 商品アクションタイプを定義するための列挙型。
export enum ProductAction {
    Use,
    Add,
}
```



### サーバースクリプトの説明

- 世界の通貨を管理するには、[ZEPETO.Multiplay.Currency](https://developer.zepeto.me/docs/multiplay-server/namespaces/ZEPETO_Multiplay_Currency/)。
- を使用して、`currency.credit()` と `currency.debit()` を使用して、希望する通貨の残高を増減させます。その後、`currency.getBalances()` を呼び出して、各通貨の現在の残高を取得します。

```typescript
currency.credit(currencyId, quantity);
currency.debit(currencyId, quantity);
currency.getBalances();
```

- 世界の製品を管理するには、[ZEPETO.Multiplay.Inventory](https://developer.zepeto.me/docs/multiplay-server/namespaces/ZEPETO_Multiplay_Inventory)。
- を使用して、`inventory.add()` と `inventory.use()` を使用して、希望する通貨の残高を増減させます。

```typescript
inventory.add(productId, quantity);
inventory.use(productId, quantity);
```

- クライアントからの通貨や商品の増減に関するリクエストを処理します。
- 使用する`loadBalance()`を使用して、ZEPETO Studioに登録された通貨情報を取得します。
- 複数の通貨がある場合、特定の通貨IDの値に基づいて条件を設定し、その通貨の残高のみを取得できます。
- 最終的な残高値をクライアントにルームメッセージとして渡します。

