GS2-Datastore

binary-data-storage-functions

GS2 Datastore allows you to store arbitrary binary data on the server.

Uploaded data can have access permission settings: “open to all”, “open to players with specified user IDs”, or “for me only”.

GS2-Datastore is primarily intended for uploading data such as UGC or racing game ghost data, and is not necessarily suitable for storing player user data.

This is because storing the amount of possessions as binary data would allow playing with modded applications that multiply items by manipulating the save data or the application itself, or by illegally increasing the amount obtained. If it is the quantity of possessions, such cheating cannot be done using a dedicated microservice like GS2-Inventory.

This is not to deny the storage of user data that does not affect the balance of the game even if tampered with, such as configuration settings.

Architecture

GS2 Datastore manages metadata that records the location of binary data storage, etc., and uses external cloud storage for the actual binary data storage. Therefore, the upload/download process requires multiple steps.

This process flow is not a concern for the game engine SDK, as it provides a wrapped high-level API. However, SDKs for various programming languages do not provide a high-level API, so users have to handle multiple steps on their own.

Upload Process

actor Player
participant "GS2-Datastore#Namespace"
participant "Cloud Storage"
Player -> "GS2-Datastore#Namespace" : Prepare upload
"GS2-Datastore#Namespace" -> Player : Cloud Storage URL
Player -> "Cloud Storage" : Upload Payload
"Cloud Storage" -> Player : OK
Player -> "GS2-Datastore#Namespace" : Done upload report
"GS2-Datastore#Namespace" -> "Cloud Storage" : Check exists
"GS2-Datastore#Namespace" -> Player : OK

Download process

actor Player
participant "GS2-Datastore#Namespace"
participant "Cloud Storage"
Player -> "GS2-Datastore#Namespace" : Prepare download
"GS2-Datastore#Namespace" -> Player : Cloud Storage URL
Player -> "Cloud Storage" : Download
"Cloud Storage" -> Player : Payload

Downloading during upload process

GS2-Datastore can update data that has already been uploaded. During the time between calling Prepare ReUpload and Done Upload, old files before the update are available for download, and no half-finished data will be downloaded.

Retrieving past versions of uploaded data

GS2 Datastore provides access to past versions of data for the past 30 days. This includes deleted data that is actually deleted 30 days after the deletion request. However, this condition may not apply if the data was deleted due to legal requirements.

Example Implementation

Uploading data

    var result = await gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).UploadAsync(
        name: "dataObject-0001",
        scope: "public",
        data: data
    );

    var item = await result.ModelAsync();
    var dataObjectId = item.DataObjectId;
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    );
    const auto Future = Domain->Upload(
        "dataObject-0001", // name
        data, // data
        "public", // scope
    );
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

Download data (specify data object ID)

    var binary = await gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DownloadAsync(
        dataObjectId: dataObjectId
    );
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    );
    const auto Future = Domain->Download(
        dataObjectId, // dataObjectId
    );
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

Download data (specify user ID and data object name)

    var binary = await gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).DataObject(
        dataObjectName: "dataObject-0001"
    ).DownloadByUserIdAndDataObjectNameAsync(
    );
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    );
    const auto Future = Domain->DownloadByUserIdAndDataObjectName(
        "dataObject-0001", // dataObjectName
    );
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

Download data uploaded by you (specify data object name)

    var binary = await gs2.Datastore.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).DataObject(
        dataObjectName: "dataObject-0001"
    ).DownloadOwnDataAsync(
    );
    const auto Domain = Gs2->Datastore->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        AccessToken
    )->DataObject(
        "dataObject-0001" // dataObjectName
    );
    const auto Future = Domain->DownloadOwnData(
    );
    Future->StartSynchronousTask();
    if (!TestFalse(WHAT, Future->GetTask().IsError())) return false;

Detailed reference.