Studio GuideWorld SDK Guide
Log In

Product API Usage Examples

The following are examples of using the Product API to manage World Currency and World Products.

This example allows you to get a basic understanding of the Product API and implement sending and receiving messages between the server and the client, so that you can easily test the granting and deducting world currencies and products.

This example includes descriptions of both the World Currency and World Product client scripts, followed by the integrated server script that handles all server-side processing, and includes the following functions:

  • Granting World Currency
  • Deducting World Currency
  • Granting World Products without Currency Deduction
  • Deducting World Products

Granting & Deducting World Currency

Below is the complete client code for managing world currency granting and deduction, and how to implement it.

Currency Client Script

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);
        });
 
        // Handles room joined events for currency UI updates
        this.multiplay.RoomJoined += (room: Room) => {
            room.AddMessageHandler("SyncCurrencyInfo", (message: CurrencyMessage) => {
                const currentCurrencyId = message.currencyId;
                const currentQuantity = message.quantity;
                this.balanceUIUpdate(currentCurrencyId, currentQuantity);
            });
        };
 
        // Button event listener for increasing currency : Request Credit
        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());
        })
 
        // Button event listener for decreasing currency : Request Debit
        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());
        })
 
    }
 
    // Requests the current amount of specified currency
    private loadCurrencyBalance(currentCurrencyId: string) {
        this.multiplay.Room?.Send("LoadBalance", currentCurrencyId);
    }
 
    // Updates the UI to reflect the current quantity of the currency
    private balanceUIUpdate(currentCurrencyId: string, currentQuantity: number) {
        this.balanceText.text = currentQuantity.toString();
    }
 
}
 
// Interface for currency sync messages
interface CurrencyMessage {
    currencyId: string,
    quantity: number,
}

Currency Client Script Description

  • When a character is loaded, a Room Message is sent to the server to load the existing balance of currency. The UI is then updated based on the balance information received from the server.
this.multiplay.Room?.Send("LoadBalance", currentCurrencyId);
  • To facilitate message exchange, the CurrencyMessage interface is defined.
interface CurrencyMessage {
    currencyId: string,
    quantity: number,
}
  • When a user increases or decreases their currency, they send a request to the server as a Room Message.
    It includes data about which currency to increase or decrease and by how much.
this.multiplay.Room?.Send("CreditCurrency", data.GetObject());
this.multiplay.Room?.Send("DebitCurrency", data.GetObject());
  • The server then processes the increase or decrease in currency and sends the final balance information to the client. The client receives this information and updates the UI.
    View the full server script
this.multiplay.RoomJoined += (room: Room) => {
    room.AddMessageHandler("SyncCurrencyInfo", (message: CurrencyMessage) => {
        const currentCurrencyId = message.currencyId;
        const currentQuantity = message.quantity;
        this.updateBalanceUI(currentCurrencyId, currentQuantity);
    });
};

Granting & Deducting World Products

Below is the complete client code for managing world product granting and deduction, and how to implement it.

Product Client Script

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());
        });
 
        // Handles room joined events for product UI updates
        this.multiplay.RoomJoined += (room: Room) => {
            room.AddMessageHandler("SyncProductInfo", (message: ProductMessage) => {
                this.StartCoroutine(this.refreshProductUI());
            });
        };
 
        // Button event listener for  the acquire item : Add Product
        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());
        })
 
        // Button event listener for  the use item : Use Product
        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);
        // If the request is successful, updates the Product UI
        if (request.responseData.isSuccess) {
            this.updateItemCountText(request.responseData.product);
        }
        else {
            console.log("Failed to load product Item.");
        }
    }
 
    private updateItemCountText(item: InventoryRecord) {
        if (item != null) {
            this.itemCountText.text = item.quantity.toString();
        }
        else {
            this.itemCountText.text = "0";
        }
    }
 
}
 
// Interface for product messages.
interface ProductMessage {
    productId: string,
    productAction: ProductAction,
}
 
// Enum for defining product action types.
export enum ProductAction {
    Use,
    Add,
}

Product Client Script Description

  • When a character loads, use the InventoryService from ZEPETO.Inventory to load the initial inventory of products. Then update the UI.
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("Failed to load product Item.");
        }
    }
  • To send and receive messages, define the ProductMessage interface. Define a ProductAction Enum for the example implementation.
interface ProductMessage {
    productId: string,
    productAction: ProductAction,
}
 
export enum ProductAction {
    Use,
    Add,
}
  • When you increase or decrease a product, you send that data to the server as a Room Message.
    It includes data about which product to increase or decrease and by how much.
this.multiplay.Room?.Send("AddProduct", data.GetObject());
this.multiplay.Room?.Send("UseProduct", data.GetObject());
  • After processing the product changes, the server sends the final inventory information to the client, which updates the UI accordingly.
    View the full server script
this.multiplay.RoomJoined += (room: Room) => {
    room.AddMessageHandler("SyncProductInfo", (message: ProductMessage) => {
        this.StartCoroutine(this.refreshProductUI());
    });
};

👍

Tips


Server Script

Below is the complete server code that manages the world currency and products, and how to implement it.

Full Server Script

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) {

        // Currency
        //Request loading currency
        this.onMessage("LoadBalance", (client, message: string) => {
            this.loadBalance(client, message);
        });
        //Request adding credit
        this.onMessage("CreditCurrency", (client, message: CurrencyMessage ) => {
            const currencyId = message.currencyId;
            const quantity = message.quantity;
            this.addCredit(client, currencyId, quantity);
        });
        //Request debiting credit
        this.onMessage("DebitCurrency", (client, message: CurrencyMessage ) => {
            const currencyId = message.currencyId;
            const quantity = message.quantity;
            this.onDebit(client, currencyId, quantity);
        });

        // Product
        //Request adding item
        this.onMessage("AddProduct", (client, message: any) => {
            const productId = message.productId;
            const quantity = message.quantity;
            this.addProduct(client, productId, quantity);
        });
        //Request using item
        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: Currency Not Enough");
            }
        } 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) {
        // OnJoin logic here
    }

    onTick(deltaTime: number): void {
        // Tick logic here
    }

    onLeave(client: SandboxPlayer, consented?: boolean) {
        // Handle leave logic here
    }

}

// Interface for currency messages
interface CurrencyMessage {
    currencyId: string,
    quantity: number,
}

// Interface for product messages.
interface ProductMessage {
    productId: string,
    productAction: ProductAction,
}

// Enum for defining product action types.
export enum ProductAction {
    Use,
    Add,
}

Server Script Description

  • Manage the world currency via ZEPETO.Multiplay.Currency.
  • Use currency.credit() and currency.debit() to increase or decrease the balance of the desired currency. Afterward, call currency.getBalances() to get the current balance for each currency.
currency.credit(currencyId, quantity);
currency.debit(currencyId, quantity);
currency.getBalances();
  • Manage world products via ZEPETO.Multiplay.Inventory.
  • Use inventory.add() and inventory.use() to increase or decrease the balance of the desired currency.
inventory.add(productId, quantity);
inventory.use(productId, quantity);
  • Handles requests from clients for increasing or decreasing currencies and products.
  • Use loadBalance() to get the currency information registered in ZEPETO Studio.
  • If there are multiple currencies, you can condition on a specific currency ID value to get the balance of only that currency.
  • Pass the final balance value to the client as a Room Message.