Guides
Log In

Multiplay World DataStorage

DataStorage

The ZEPETO World Data Storage component is the ability to store data by client (player connected to the server).

It is commonly used to store data such as inventory items, skill points, and levels.

Data is stored on a ZEPETO account basis and must be added to the server logic (World.multiplay package β†’ index.ts).

User data stored through DataStorage can be viewed and changed through World Data Management.

πŸ“˜

Please refer to the following guide. [World Data Management]


Defining Function

declare module 'ZEPETO.Multiplay.DataStorage' {   
    interface DataStorage {
        set<T>(key: string, value: T): Promise<boolean>;
        mset<T>(keyValueSet: { key: string; value: T; }[]): Promise<boolean>;
        get<T>(key: string): Promise<T>;
        mget<T>(keys: string[]): Promise<{ [key: string]: T }>;
        remove(key: string): Promise<boolean>;
    }
    function loadDataStorage(userId: string): Promise<DataStorage>;
}

To use the ZEPETO.Multiplay.DataStorage module, you must complete the import statement as follows:

import { DataStorage } from 'ZEPETO.Multiplay.DataStorage';

DataStorage.set(key, value)

A set function is a function that stores data.
It is stored with key and value as parameters, and the key value can be freely defined and used.

❗️

Caution

  • On the local server in the Unity Editor environment, data is not preserved when the server is shut down and run again.
  • After World deployment, data is stored in ZEPETO DB and maintained.
  • Storage capacity is limited to 10 KB. (May be changed later.)
await playerStorage.set("level", 1);

DataStorage.get(key)

The get function is a function that looks up data.
Enter key as a parameter to query the value. Returns null if a key that does not exist is queried.

let playerLevel = await playerStorage.get("level") as number;

β–Ό Example code using Save & Load to record user levels

import { DataStorage } from 'ZEPETO.Multiplay.DataStorage';
 
async onJoin(client: SandboxPlayer) {
    // Load current player's data storage
    const playerStorage: DataStorage = client.loadDataStorage();
    let playerLevel = await playerStorage.get("level") as number;
 
    if (playerLevel == null) {
        playerLevel = 1;
    }
 
    await playerStorage.set("level", playerLevel);
}

DataStorage Multi-Get/Multi-Set

You can import or store multiple values at a time.

❗️

Caution

  • Features available in ZEPETO World Package 1.12.2 and later.

DataStorage.mget(keys)

The mget function allows Data Storage to fetch multiple values at a time.

❗️

Caution

  • In mget(keys), keys must be an array.
  • Entering an empty value results in an error.
  • Be sure to add an exception handling code for whether the key value is valid by referring to the example code.

DataStorage.mset({key, value})

The mset function allows DataStorage to store multiple values at a time.
Enter and save a keyValueSet array in the format {key,value} as a parameter.

❗️

Caution

  • If you specify a generic type, only the same type of data can be stored.
  • If you do not specify it as generic, you can store each other's type of data.
  • If you enter an empty array value, false is returned.

β–Ό DataStorage Multi-Get/Multi-Set Use Example Code

  • Please use the error handling syntax.
this.onMessage<SaveValue>('save', async (client: SandboxPlayer, message: SaveValue) => {
        const storage = client.loadDataStorage();
        try {
            // mset (multi key-value) store
            const success = await storage.mset<number>([
                {
                    key: 'key1',
                    value: 1
                },
                {
                    key: 'key2',
                    value: 2
                }
            ]);
            // If successful
            if (success) {
                // Get the values of key1 and key2 at once
                const keys = ['key1', 'key2'];
                const keyValeus = await storage.mget(keys);
                keys.forEach(key => {
                    const value = keyValeus[key];
                    if (key === 'key1' && value !== null && value !== undefined) {
                        console.log(value);
                    } else if (key === 'key2' && value !== null && value !== undefined) {
                        console.log(value);
                    }
                });
            }
        } catch(error) {
            let systemError = (error as SystemError);
             
            if (systemError.code === DataStorageError.Unknown || systemError.code === DataStorageError.NetworkError) { // System error or network error
                console.log(systemError.message);
            } else if (systemError.code === DataStorageError.KeyConstraintViolated) { // Key constraint violated
                console.log(systemError.message);                   
            } else if (systemError.code === DataStorageError.ValueConstraintViolated) { // Value constraint violated
                console.log(systemError.message);                   
            }
        }
    });

Manage DataStorage based on UserId

Read/Write/Delete Data Storage based on UserId.

❗️

Caution

  • Features available in ZEPETO World Package 1.9.0 and later.
  • Please fill out the server code index.ts Sandbox.

πŸ‘

Previously, only the accessor's own Data Storage was accessible, and there was no way to get information such as other people's scores or abilities.

First, to get user information, we define Schema Types and Room State as follows:

469

β–Ό Example code for using UserId-based DataStorage

import { Sandbox, SandboxOptions, SandboxPlayer } from 'ZEPETO.Multiplay';
import { DataStorage, loadDataStorage } from 'ZEPETO.Multiplay.DataStorage';
import { UserInfo } from 'ZEPETO.Multiplay.Schema';
 
interface TargetData {
    lastJoinRoom: string;
    lastJoinTime: string;
}
 
export default class extends Sandbox {
 
    onCreate(options: SandboxOptions) {
        this.onMessage("TargetData", (client: SandboxPlayer, targetData: TargetData) => {
            this.saveTargetData(client, targetData);
        });
 
        this.onMessage("GetTargetData", (client: SandboxPlayer, userId: string) => {
            this.loadTargetData(client, userId);
        });
 
    }
 
    onJoin(client: SandboxPlayer) {
        const user = new UserInfo();
        user.sessionId = client.sessionId;
        user.userId = client.userId;
        this.state.UserInfos.set(client.userId, user);
    }
 
    onLeave(client: SandboxPlayer, consented?: boolean) {
        this.state.UserInfos.delete(client.userId);
    }
 
    async saveTargetData(client: SandboxPlayer, targetData: TargetData) {
        console.log(`save target data (${client.userId})\n ${JSON.stringify(targetData)}`);
        const playerStorage: DataStorage = client.loadDataStorage();
        const result = await playerStorage.set("targetData", targetData);
        client.send("Log", `Save Result : ${result}`);
    }
 
    async loadTargetData(client: SandboxPlayer, userId: string) {
        console.log(`load target data (${userId})`);
        const userStorage: DataStorage = await loadDataStorage(userId);
        const targetData = await userStorage.get<TargetData>("targetData");
        console.log(JSON.stringify(targetData));
 
        if (targetData) {
            client.send("TargetData", targetData);
        } else {
            const empty: TargetData = {
                lastJoinRoom: "",
                lastJoinTime: "",
            }
 
            client.send("TargetData", empty);
        }
    }
}

In the example above, the key points are as follows:

this.state.UserInfos.set(client.userId, user);Stores data in DataStorage for a specific userID.
const userStorage: DataStorage = await loadDataStorage(userId);

const targetData = await userStorage.get("targetData");
Reads data from a specific user in asynchronous form.

It then imports data for a specific key value.
this.state.UserInfos.delete(client.userId);Deletes data to DataStorage for a specific userID.

❗️

Caution

  • If you use UserInfos.delete(), the target UserID's data will be deleted and it cannot be recovered, so please use it carefully.
  • The World developer is responsible for deleting data using the UserInfos.delete() script.

PlayerPrefs - Saving data to the device

ClientStorage

Provides the ability to save players to the device they are connecting to.
It can be called from the client ZEPETO Script, and data will not be preserved if you delete the app or change the device.

It supports use in the same way as PlayerPrefs in Unity, and the storage capacity is limited to 10KB.


β–Ό Example code for checking the number of plays using the Save & Load function

import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { PlayerPrefs } from 'UnityEngine';
 
export default class ClientSaveLoad extends ZepetoScriptBehaviour {
 
    playCntKey: string = 'PlayCnt';
 
    Start() {
        if (PlayerPrefs.HasKey(this.playCntKey)) {
            PlayerPrefs.SetInt(this.playCntKey, PlayerPrefs.GetInt(this.playCntKey) + 1);
            console.log(`PlayCnt : ${ PlayerPrefs.GetInt(this.playCntKey) }`);
        } else {
            PlayerPrefs.SetInt(this.playCntKey, 1);
            console.log('PlayCnt : 1');
        }
    }
}

πŸ“˜

View Unity PlayerPrefs information

https://docs.unity3d.com/ScriptReference/PlayerPrefs.html