# PC SDK Unreal Integration Guide

# Introduction

The STOVE platform for games provides integrated services. All processes of game release, including game distribution and sales, community, and indicator analysis, can be handled in one-stop.

With the STOVE PC SDK (Unreal version, hereafter referred to as PC SDK), you can easily integrate the services provided by the Stove platform into your game.

This section describes how to integrate the PC SDK.

confirm if this is your first time integrating the PC SDK, please first read PC SDK Unreal Walkthrough

# Preparation in advance

  • Only works with UNREAL Engine 4.22.3 and above, lower versions require the [Native StovePCSDK] (../Integration/native.md) integration.
  • Check that you have issued the stove subscription account and the App key, App secret, and Game Id for the released game from STOVE Studio (opens new window).
  • Make sure you have Visual Studio 2015 Update 3 or higher compiler installed.
  • Download the latest Unreal distribution file (Shown as Plugin) from the PC SDK Download page.

# Plugin Distribution File Configuration

Figure1

# 1) include folder

After downloading and unpacking Plugin, the following files are included in Plugins\StoveSDKPlugin\Binaries\ThirdParty\StoveSDKPluginLibrary\include folder.

  • StovePCCallback.h
    • Header file for callback definitions to receive callbacks after calls to the Stove plugin and NativeSDK API.
  • StovePCEnum.h
    • This header file contains enumerations defined by the NativeSDK, such as error, API type, and asynchronous status values.
  • StovePCDefine.h
    • Declared API call result (StovePCResult), error result structure (FStoveError), callback function, API request/response parameters, etc. used for communication between Stove plugin and NativePCSDK.
  • StovePCSDK.h
    • API functions used for communication between the Stove plugin and NativePCSDK are declared.

# 2) Unreal API Include folder

After downloading and extracting Plugin, the following files are included in Plugins\StoveSDKPlugin\Source\StoveSDKPlugin\Public folder.

  • StoveSDKEnum.h
    • Enum defined in stove plug-in is declared.
  • StoveSDKNativeCallback.h
    • This is a file that implements a callback function that delivers events between the stove plug-in and NativePCSDK.
  • StoveSDKObject.h
    • This is a UObject-type class that receives callbacks and UE4 API that wraps the NativePCSDK API that inherits from UObject.
  • StoveSDKPlugin.h
    • Module wrapper class to load NativePCSDK module from Stove plugin.
  • StoveSDKStruct.h
    • Struct set header to pass after API call from stove plugin.
  • StoveSDKVersion.h
    • This file is used to check the Unreal version in Stove.
  • StoveSDKWebInterface.h
    • This is an interface class for linking with StoveWebPlugin provided by Stove.

# 3) Bin folder

Under the Plugins\StoveSDKPlugin\Binaries\ThirdParty\StoveSDKPluginLibrary\bin folder, binaries required for each platform (x64) and configuration (Release) are included.

  • concrt140.dll
  • msvcp100.dll
  • msvcp140.dll
  • msvcr100.dll
  • sgup_api(64).dll
  • StovePCSDK.dll
  • vcruntime140.dll

Except for StovePCSDK.lib, the files in the list above must be distributed together when distributing the game client to end users.

# 4) StoveSDKPlugin.uplugin

This file is for recognizing plugins in Unreal. It should be placed inside Plugins within your game project.

# Integration

  • StovePCSDK_Unreal uses Unreal Engine's UStoveSDKObject class which is an UObject type class. Here, we have redefined the data types, interfaces, and callback functions of the StovePCSDK library. Before integrating, use after inheriting the defined UStoveSDKObject of Plugin and configuring UMyStoveSDKObject in the game engine.

  • Prefix
    There is a rule with Unreal Engine that the prefix U is added to the classes that inherit the UObject type.

We call the interface imported from the inherited UObject to the Plugin through Super.

  • Super
    The keyword provided by Unreal to call an inherited parent's function is Super.
FStoveResult UMyStoveSDKObject::StoveSDKInit(const FStoveConfig& fConfig)
{
    FStoveResult fResult = Super::StoveSDKInit(fConfig);
}
1
2
3
4

For the Plugin environment configuration, refer to the Configuring the project environment, categories 1 to 3, in PC SDK Unreal Walkthrough

# 1) Config, Callback Settings

Suppose you wish to initialize the PC SDK. In that case, you must fill the FStoveConfig values and call the UStoveSDKObject::StoveSDKInit function of the inherited Actor.
Refer to the code below and fill in the field values of the FStoveConfig structures.

FStoveConfig fConfig{"LIVE",
                    "YOUR_APP_KEY",
                    "YOUR_SECRET_KEY",
                    "YOUR_GAME_ID",
                    StovePCLogLevel::STOVE_PC_LOG_LEVEL_DEBUG,
                    ""};
1
2
3
4
5
6

For the description of the FStoveConfig structure, refer to the StoveSDKStruct.h file in the Plugins\StoveSDKPlugin\Source\StoveSDKPlugin\Public folder.

To call the API of the PC SDK in the game project and check the result, you need to use the callback function. The callback function used in the game project is as follows.

    //StovePCSDK Callback
public:
    void OnError(FStoveError Error) final;
    void OnInitComplete() final;
    void OnToken(FStoveToken Token) final;
    void OnUser(FStoveUser User) final;
    void OnOwnership(int Size, FStoveOwnership* Ownerships) final;
1
2
3
4
5
6
7

The OnError, OnInitComplete and OnOwnership callback functions must work together. You can integrate the rest of the callback functions only when necessary. For example, suppose you only use the Ownership function. In that case, you can implement it by defining it in the game project, as shown below.

/*As for when only using the Ownership function,
apart from the essential callbacks OnError, OnInitcomplte,
connect only the OnOwnership callback additionally.*/
void UMyStoveSDKObject::OnInitComplete()
{
    // Process detail after successful initialization
}

void UMyStoveSDKObject::OnError(FStoveError Error)
{
    // Process detail of the error
}

void UMyStoveSDKObject::OnOwnership(int Size, FStoveOwnership* Ownerships)
{
    // Process detail after the viewing ownership
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2) SDK Initialization

Before using the API of PC SDK, enter the initialization code as shown below in the UMyStoveSDKObject::StoveSDKInit function of MyStoveSDKObject.cpp for initialization.

FStoveResult UMyStoveSDKObject::StoveSDKInit(const FStoveConfig& Config)
{
    FStoveResult ErrorResult = Super::StoveSDKInit(Config);
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*StovePCSDK init Success*/
        
    }
}
1
2
3
4
5
6
7
8
9

The UMyStoveSDKObject::StoveSDKInit function immediately returns the FStovePCResult enum type value after checking only the validity of config and callback.
In case of success, it returns a value of STOVE_PC_NO_ERROR. In case of failure, it returns the corresponding error code, and you need to quit the game. For the entire list of error codes, refer to the StovePCDefine.h file.

The UMyStoveSDKObject::StoveSDKInit function handles other operations asynchronously, except config and callback validation.
When you have completed the asynchronous operation, it calls the UMyStoveSDKObject::OnInitComplete callback. And it calls UMyStoveSDKObject::OnError callback when there is an error.
If an error occurs during initialization, you can check the error code and message through the StovePCError structure passed to the UMyStoveSDKObject::OnError function. The fError.result.result value of the StovePCError structure parameter is the same as the StovePCResult enum. So you can infer the error condition from the error code.

void UMyStoveSDKObject::OnInitComplete()
{
    OnLog("[OnInitComplete]");
}
 
void UMyStoveSDKObject::OnError(const FStoveError& Error)
{
    switch (Error.FunctionType)
    {
    case STOVE_PC_INIT:
    case STOVE_PC_GET_USER:
    case STOVE_PC_GET_OWNERSHIP:
        QuitApplicationDueToError();
        break;
    }
}

void UMyStoveSDKObject::QuitApplicationDueToError()
{
        // After showing the user a message about app outage rather than stopping it immediately
        // Depending on user action (e.g. clicking the exit button), you may want to terminate the app.
        // If so, implement your own logic.
        // Recommended messages for required pre-task errors are as follows.
        // Korean: The required pre-task failed to operate and the game has been terminated.
        // Other Languages: The required pre-task fails and exits the game.
	OnStoveLog("QuitApplicationDueToError");
	FGenericPlatformMisc::RequestExit(false);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

Before the UMyStoveSDKObject::OnInitComplete callback comes, if it is necessary to view the initialization state value of the PC SDK, you can use the UMyStoveSDKObject::GetInitState function.

/*After calling StovePC.Init..*/
while (Super::GetInitState().state
    == StovePCInitState::STOVE_PC_INIT_PENDING)
{
    FPlatformProcess::Sleep(0.5f);
    RunCallback();
}
if (Super::GetInitState().state
    == StovePCInitState::STOVE_PC_INIT_COMPLETE)
{
    /*Initialization Complete
    OnInitComplete callback is called*/
    return FStoveResult{STOVE_PC_NO_ERROR};
}
else
{
    /*Initialization failed
    OnError callback is called*/
    return FStoveResult{ STOVE_PC_NO_ERROR };;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3) Cautions when integrating the SDK

confirm When setting the log level of the FStovePCConfig structure, which is a parameter of the StoveSDKInit function, enter the value StovePCLogLevel::STOVE_PC_LOG_LEVEL_DEBUG for the Debug build. For the official build, please set StovePCLogLevel::STOVE_PC_LOG_LEVEL_ERROR to prevent unnecessary log creation.

confirm If the GetToken, GetUser, GetOwnership methods are called before initialization is complete, it may not return normal results. In other words, you must call the GetToken, GetUser, GetOwnership methods after receiving the callback of OnInitComplete to receive normal results.

# 4) SDK Termination

After using the PC SDK, call the StoveSDKUnInit function to clean up the resources in use. After reaching the StoveSDKUnInit function, the API of PC SDK does not work.

FStoveResult UMyStoveSDKObject::StoveSDKUnInit()
{
    FStoveResult ErrorResult = Super::StoveSDKUnInit();
    if (ErorrResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*Success Process*/
    }
    return ErrorResult;
}
1
2
3
4
5
6
7
8
9

# 5) Receive user information

Use the UMyStoveSDKObject::StoveSDKGetUser function to retrieve the logged-in user information in STOVE Launcher.

FStoveResult UMyStoveSDKObject::StoveSDKGetUser()
{
    FStoveResult ErrorResult = Super::StoveSDKGetUser();
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*Success Process*/
    }

    return ErrorResult; 
}
1
2
3
4
5
6
7
8
9
10

The UMyStoveSDKObject::OnUser callback is called when the UMyStoveSDKObject::StoveSDKGetUser function is processed properly.
You can know the user's memberNo, Nickname, Game User ID information through the StovePCUser structure passed to the callback.

void UMyStoveSDKObject::OnUser(FStoveUser User)
{
    /*User Information Output*/
    OnLog("[User]");
    OnLog("MemberNo : %u", User.MemberNo);
    OnLog("Nickname : %s", *(User.Nickname));
    OnLog("GameUserId: %s", *(User.GameUserId));
}
1
2
3
4
5
6
7
8

# 6) Get Token Information

Get token information of the user who logged in to STOVE launcher with UMyStoveSDKObject::StoveSDKGetToken function.

FStoveResult UMyStoveSDKObject::StoveSDKGetToken()
{
    FStoveResult ErrorResult = Super::StoveSDKGetToken();
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*Success Process*/
    }
 
    return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10

The UMyStoveSDKObject::OnToken callback is called when the UMyStoveSDKObject::StoveSDKGetToken function is processed properly.
It contains the token string in the StovePCToken structure delivered to the callback.

void UMyStoveSDKObject::OnToken(FStoveToken Token)
{
    /*Token Information Output*/
    OnLog("AccessToken : %s", *(Token.AccessToken));
}
1
2
3
4
5

confirm What is a token? It is the access token of the logged-in user in STOVE Launcher, and the game server passes this access token to the stove authentication server to validate the logged-in user.
For a detailed explanation of Access Token, please get in touch with store.support@smilegate.com for technical support.

# 7) Get ownership information

With the UMyStoveSDKObject::StoveSDKGetOwnership function, you can inquire whether the user of the STOVE launcher has purchased and owns a game registered in STOVE Studio.


FStoveResult UMyStoveSDKObject::StoveSDKGetOwnership()
{
    FStoveResult Result = Super::StoveSDKGetOwnership();
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*Success Process*/
        /*It delivers information about ownership to the OnOwnership callback.*/ 
    }

    return ErrorResult; 
}
1
2
3
4
5
6
7
8
9
10
11
12

The UMyStoveSDKObject::OnOwnership callback is called when the UMyStoveSDKObject::StoveSDKGetOwnership function is processed properly.
For detailed information on the StovePCOwnership structure, refer to the StovePCDefine.h file.

Below is an example code that determines the purchase status of a game in the OnOwnership callback. If the game is without DLC, the confirmation code for lines 20 to 23 is unnecessary.

void UMyStoveSDKObject::OnOwnership(int size, FStoveOwnership* Ownership)
{
    bool owned = false;
 
    FStoveOwnership* data = fOwnership;
    for (int i = 0; i < size; i++, data++)
    {
        if ((data->MemberNo != LOGIN_USER_MEMBER_NO /* StovePCUser Structural memberNo*/)
            || (data->OwnershipCode != 1 /* 1: Having the ownership, 2: Ownership removed (Cancelling the purchase)*/))
        {
            continue;
        }

        if (0 == wcscmp(L"YOUR_GAME_ID", *(data->GameId)) && data->GameCode == 3 /*3: BASIC, 4: DEMO*/)
        {
           owned = true; // Set ownership verification variable to true
        }

        /*Required only for games selling DLC*/
        if (0 == wcscmp(L"YOUR_DLC_ID", *(data->GameId)) && data->GameCode == 5 /* 5: DLC*/)
        {
            /*User owns YOUR_DLC_ID(DLC). allow DLC play*/
        }
    }

     if(owned)
    {
        // Write game entry logic after ownership verification is usually completed
    }
    else
    {
        // After ownership verification fails, end the game and write an error message display logic
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  • You can play the game after logging in to the STOVE launcher with the account that purchased the game (with ownership).

  • After logging in to the STOVE launcher with an account that does not own the game, the following guide message (example) is output when you execute the exe and then terminate the game.

    • "Please log in to STOVE Client with the account that has purchased the game."

    confirm You don't need an account with game ownership to test the ownership feature. See FAQ.

# 9) Language translation 2.6.0

Translate languages with UMyStoveSDKObject::StoveSDKTranslateLanguage function.
PC SDK provides a translation for a specific string based on the set language information.
A specific string is managed as a String ID managed by the PC SDK.
If the game implements the PC SDK popup UI directly, the string displayed in the UI must display the translated string through the UMyStoveSDKObject::StoveSDKTranslateLanguage function.

FString Translated=UMyStoveSDKObject::StoveSDKTranslateLanguage("STRING_ID");
1

Precautions

Returns an English translation if there is no translation of a specific string for the language set in the PC SDK.
For exceptions or unsupported string IDs, the input parameter (string ID) is returned as it is.

# Check Error

The errors that occur while using the PC SDK are usually one of two cases.

# StovePCResult enum value returned after calling the function

All PC SDK's functions will return a StovePCResult enum value immediately after calling to mark whether the call was successful.
The entire value can be checked in the PC SDK Error Code page.

# The StovePCError structure delivered through the OnError callback.

Suppose an error occurs in an asynchronous function during the PC SDK function. In that case, it calls a UMyStoveSDKObject::OnError callback and delivers a StovePCError structure with a description of the error.

/*Delivered when an OnError callback is called.*/
struct StovePCError
{
    /*enum value which indicates the called function*/
    StovePCFunctionType functionType;

    /*enum value which indicates the occurred error type*/
    StovePCResult result;

    /*Occurred Error Message*/
    char* message;

    /*The corresponding error code if an external error (http error, external module error) has occurred*/
    int externalError; 
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Integrating pop-ups

The PC SDK provides APIs to integrate popups into your game. Pop-ups supported by PC SDK include automatic, manual, news, coupon, and community.
The PC SDK provides data for popups to the game. The game creates a pop-up view using the provided data.
Each popup is defined as follows.

  • Automatic pop-up: Pop-up that is most exposed on the game lobby screen and shows advertisements and events
  • Manual pop-up: Pop-up showing registered events corresponding to the resource key -News pop-up: A pop-up that collects and shows announcement posts at once
  • Coupon pop-up: Pop-up showing the coupon registration page
  • Community popup: Popup showing the game community page

In order to use the PC SDK popup API, the metadata registration of the popup integrated with Partners must be preceded.

# 1) Callback setting

To communicate with the PC SDK using the pop-up API, the game must override the callback function defined in the UStoveSDKObject class below.

{
//StovePCSDK Callback
public:
    void OnError(FStoveError Error) final;
    void OnInitComplete() final;
    void OnToken(FStoveToken Token) final;
    void OnUser(FStoveUser User) final;
    void OnOwnership(int Size, FStoveOwnership* Ownerships) final;
}
1
2
3
4
5
6
7
8
9

You are not required to implement the OnAutoPopup, OnManualPopup, OnNewsPopup, OnCouponPopup, OnCommunityPopup callbacks.
You only need to implement and connect the necessary callback functions according to the pop-up used in the game.

/*As for when only using the Ownership function,
apart from the essential callbacks OnError, OnInitcomplte,
connect only the OnOwnership callback additionally.*/
void UMyStoveSDKObject::OnInitComplete()
{
    // Process details after successful initialization
}

void UMyStoveSDKObject::OnError(FStoveError fError)
{
    // Process details of the error
}

void UMyStoveSDKObject::OnOwnership(int size, FStoveOwnership* fOwnership)
{
    // Process details after ownership has been viewed
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2) Game Profile Settings

Set game world and character information with UMyStoveSDKObject::StoveSDKSetGameProfile function.
Set information is used in pop-ups, so it must be set before using pop-ups.
The validity of the game profile is not checked separately. Therefore, you must enter the correct value by proceeding with validation (null) when entering.
The entered game profile is only valid for the life cycle of PCSDK.
That is, whenever PCSDK is initialized, the game world and character information must be set by calling the UMyStoveSDKObject::StoveSDKSetGameProfile function.

// input parameters
// const FString& WorldId: The game's world identifier
// const FString& CharacterNo: character identifier
 

FStoveResult UMyStoveSDKObject::StoveSDKSetGameProfile(const FString & WorldId, const FString & CharactorNo)
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKSetGameProfile(WorldId, CharactorNo);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
           // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 3) Get automatic pop-up information

Search information about auto popup with UMyStoveSDKObject::StoveSDKGetAutoPopup function.

FStoveResult UMyStoveSDKObject::StoveSDKGetAutoPopup()
{
     /*Add the 'walkthrough' codes here.*/
     FStoveResult ErrorResult = Super::StoveSDKGetAutoPopup();

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // success handling
     }
     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11

When the UMyStoveSDKObject::StoveSDKGetAutoPopup function is successfully processed, the UMyStoveSDKObject::OnAutoPopup callback is called.
The FStoveAutoPopup structure passed to the callback contains the URL to the autopopup.
The FStovePopupRequestHeader structure passed to the callback contains name/value pairs of headers to be set when requesting URLs.

void UMyStoveSDKObject::OnAutoPopup(int Size, FStoveAutoPopup * AutoPopups, int HeaderSize, FStovePopupRequestHeader * Headers)
{
     OnLog("[AutoPopup]");
  
     OnLog("AutoPopup size = %d ", Size);
  
 
     for (int i = 0; i < Size; i++, AutoPopups++)
     {
         OnLog("- AutoPopup[%d].Origin : %s", i, *(AutoPopups->Origin));
         OnLog("- AutoPopup[%d].Id : %d", i, AutoPopups->Id);
         OnLog("- AutoPopup[%d].Url : %s", i, *(AutoPopups->Url));
  
         OnLog("- AutoPopup[%d].Control.UI.DisallowedDay :%d", i, AutoPopups->Control.UI.DisallowedDay);
  
         OnLog("- AutoPopup[%d].Control.UI.Visible.BackButton :%s", i, AutoPopups->Control.UI.Visible.BackButton ? TEXT("true") : TEXT("false"));
         OnLog("- AutoPopup[%d].Control.UI.Visible.CloseButton :%s", i, AutoPopups->Control.UI.Visible.CloseButton ? TEXT("true") : TEXT("false"));
         OnLog("- AutoPopup[%d].Control.UI.Visible.DisallowedButton :%s", i, AutoPopups->Control.UI.Visible.DisallowedButton ? TEXT("true") : TEXT("false"));
         OnLog("- AutoPopup[%d].Control.UI.Visible.ForwardButton :%s", i, AutoPopups->Control.UI.Visible.ForwardButton ? TEXT("true") : TEXT("false"));
         OnLog("- AutoPopup[%d].Control.UI.Visible.HomeButton :%s", i, AutoPopups->Control.UI.Visible.HomeButton ? TEXT("true") : TEXT("false"));
         OnLog("- AutoPopup[%d].Control.UI.Visible.NavigationBar :%s", i, AutoPopups->Control.UI.Visible.NavigationBar ? TEXT("true") : TEXT("false"));
         OnLog("- AutoPopup[%d].Control.UI.Visible.RefreshButton :%s", i, AutoPopups->Control.UI.Visible.RefreshButton ? TEXT("true") : TEXT("false"));
  
         OnLog("- AutoPopups[%d].Control.UI.CloseButtonImage.Normal.FileId :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Normal.FileId));
         OnLog("- AutoPopups[%d].Control.UI.CloseButtonImage.Normal.FileUrl :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Normal.FileUrl));
         OnLog("- AutoPopups[%d].Control.UI.CloseButtonImage.Pressed.FileId :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Pressed.FileId));
         OnLog("- AutoPopups[%d].Control.UI.CloseButtonImage.Pressed.FileUrl :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Pressed.FileUrl));
  
         OnLog("- AutoPopup[%d].Control.UI.CloseButtonImage.Type :%d", i, AutoPopups->Control.UI.CloseButtonImage.Type);
  
     }
  
     OnLog(" - RequestHeader size = %d ", HeaderSize);
  
     for (int i = 0; i < HeaderSize; i++, Headers++)
     {
         OnLog(" - Header[%d].Name : %s", i, *(Headers->Name));
         OnLog(" - Header[%d].Value : %s", i, *(Headers->Value));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

Precautions

Even if the success callback (OnAutoPopup) is executed, there are cases where the size callback parameter is 0. At this time, an empty array is passed to the AutoPopups callback parameter.
Before using the AutoPopups callback parameter, you must first check the Size callback parameter and decide whether or not to open a popup. In this case, check Partners' automatic pop-up settings.

The exposure order of auto popups must be the same as the order of AutoPopups array elements. For example, if the AutoPopups array contains three elements [A,B,C], then the popups should be exposed in the order A, B, C.

If an error occurs while running the UMyStoveSDKObject::StoveSDKGetAutoPopup function, the UMyStoveSDKObject::OnError callback is called.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
403000 Invalid Access Error
400000 Wrong API usage Error
400001 Not Found Error
400002 Not Match Error
400003 Already exist
500001 Internal Interaction Error
900000 Unknown Service Error

# 4) Obtain manual pop-up information

Use the UMyStoveSDKObject::StoveSDKGetManualPopup function to retrieve information about manual popup.

// input parameters
// const FString& ResourceKey: Manual pop-up identifier registered by Partners
  
FStoveResult UMyStoveSDKObject::StoveSDKGetManualPopup(const FString& ResourceKey)
{
     /*Add the 'walkthrough' codes here.*/
     FStoveResult ErrorResult = Super::StoveSDKGetManualPopup(ResourceKey);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // success handling
     }
     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

When the UMyStoveSDKObject::StoveSDKGetManualPopup function is successfully processed, the UMyStoveSDKObject::OnManualPopup callback is called.
The FStoveManualPopup structure passed to the callback contains the URL for the manual popup.
The FStovePopupRequestHeader structure passed to the callback contains name/value pairs of headers to be set when requesting URLs.

void UMyStoveSDKObject::OnManualPopup(int Size, FStoveManualPopup* ManualPopups, int HeaderSize, FStovePopupRequestHeader* Headers)
{
     /*Add the 'walkthrough' codes here.*/
     OnLog("[ManualPopup]");
 
     OnLog("ManualPopup Size = %d ", Size);
 
     for (int i = 0; i < Size; i++, ManualPopups++)
     {
 
         OnLog("- ManualPopup[%d].Origin : %s", i, *(ManualPopups->Origin));
         OnLog("- ManualPopup[%d].ResourceKey : %s", i, *(ManualPopups->ResourceKey));
         OnLog("- ManualPopup[%d].Id : %d", i, ManualPopups->Id);
         OnLog("- ManualPopup[%d].Url : %s", i, *(ManualPopups->Url));
 
         OnLog("- ManualPopup[%d].Control.UI.DisallowedDay :%d", i, ManualPopups->Control.UI.DisallowedDay);
 
         OnLog("- ManualPopup[%d].Control.UI.Visible.BackButton :%s", i, ManualPopups->Control.UI.Visible.BackButton ? TEXT("true") : TEXT("false"));
         OnLog("- ManualPopup[%d].Control.UI.Visible.CloseButton :%s", i, ManualPopups->Control.UI.Visible.CloseButton ? TEXT("true") : TEXT("false"));
         OnLog("- ManualPopup[%d].Control.UI.Visible.DisallowedButton :%s", i, ManualPopups->Control.UI.Visible.DisallowedButton ? TEXT("true") : TEXT("false"));
         OnLog("- ManualPopup[%d].Control.UI.Visible.ForwardButton :%s", i, ManualPopups->Control.UI.Visible.ForwardButton ? TEXT("true") : TEXT("false"));
         OnLog("- ManualPopup[%d].Control.UI.Visible.HomeButton :%s", i, ManualPopups->Control.UI.Visible.HomeButton ? TEXT("true") : TEXT("false"));
         OnLog("- ManualPopup[%d].Control.UI.Visible.NavigationBar :%s", i, ManualPopups->Control.UI.Visible.NavigationBar ? TEXT("true") : TEXT("false"));
         OnLog("- ManualPopup[%d].Control.UI.Visible.RefreshButton :%s", i, ManualPopups->Control.UI.Visible.RefreshButton ? TEXT("true") : TEXT("false"));
 
         OnLog("- ManualPopup[%d].Control.UI.CloseButtonImage.Normal.FileId :%s", i, *(ManualPopups->Control.UI.CloseButtonImage.Normal.FileId));
         OnLog("- ManualPopup[%d].Control.UI.CloseButtonImage.Normal.FileUrl :%s", i, *(ManualPopups->Control.UI.CloseButtonImage.Normal.FileUrl));
         OnLog("- ManualPopup[%d].Control.UI.CloseButtonImage.Pressed.FileId :%s", i, *(ManualPopups->Control.UI.CloseButtonImage.Pressed.FileId));
         OnLog("- ManualPopup[%d].Control.UI.CloseButtonImage.Pressed.FileUrl :%s", i, *(ManualPopups->Control.UI.CloseButtonImage.Pressed.FileUrl));
 
         OnLog("- ManualPopup[%d].Control.UI.CloseButtonImage.Type :%d", i, ManualPopups->Control.UI.CloseButtonImage.Type);
 
     }
 
     OnLog("- RequestHeader Size = %d ", HeaderSize);
 
     for (int i = 0; i < HeaderSize; i++, Headers++)
     {
         OnLog("- Header[%d].Name : %s", i, *(Headers->Name));
         OnLog("- Header[%d].Value : %s", i, *(Headers->Value));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

Precautions

Even if the success callback (OnManualPopup) is executed, there are cases where the size callback parameter is 0.
At this time, an empty array is passed to the ManualPopups callback parameter. Before using the ManualPopups callback parameter, you must first check the Size callback parameter and decide whether or not to open a popup.
In this case, check the manual pop-up settings of Partners.

The display order of manual popups must be the same as the order of ManualPopups array elements. For example, if the ManualPopups array contains three elements [A,B,C], then the popups should be exposed in A, B, C order.

If an error occurs while executing the UMyStoveSDKObjcet::StoveSDKGetManualPopup function, the UMyStoveSDKObjcet::OnError callback is called.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
403000 Invalid Access Error
400000 Wrong API usage Error
400001 Not Found Error
400002 Not Match Error
400003 Already exist
500001 Internal Interaction Error
900000 Unknown Service Error

# 5) Get news pop-up information

Use the UMyStoveSDKObject::StoveSDKGetNewsPopup function to retrieve information about the news popup.

FStoveResult UMyStoveSDKObject::StoveSDKGetNewsPopup()
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKGetNewsPopup();
     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
       // success handling
        
     }
}
1
2
3
4
5
6
7
8
9
10
11

When the UMyStoveSDKObject::StoveSDKGetNewsPopup function is successfully processed, the UMyStoveSDKObject::OnNewsPopup callback is called.
The FStoveNewsPopup structure passed to the callback contains the URL to the newspopup.
The FStovePopupRequestHeader structure passed to the callback contains name/value pairs of headers to be set when requesting URLs.

void UMyStoveSDKObject::OnNewsPopup(FStoveNewsPopup NewsPopup, int HeaderSize, FStovePopupRequestHeader* Headers)
{
     /*Add the 'walkthrough' codes here.*/
     OnLog("[NewsPopup]");
 
     OnLog("- NewsPopup.Origin : %s", *(NewsPopup.Origin));
     OnLog("- NewsPopup.Id : %d", NewsPopup.Id);
     OnLog("- NewsPopup.Url : %s", *(NewsPopup.Url));
 
     OnLog("- NewsPopup.Control.UI.DisallowedDay :%d", NewsPopup.Control.UI.DisallowedDay);
 
     OnLog("- NewsPopup.Control.UI.Visible.BackButton :%s", NewsPopup.Control.UI.Visible.BackButton ? TEXT("true") : TEXT("false"));
     OnLog("- NewsPopup.Control.UI.Visible.CloseButton :%s", NewsPopup.Control.UI.Visible.CloseButton ? TEXT("true") : TEXT("false"));
     OnLog("- NewsPopup.Control.UI.Visible.DisallowedButton :%s", NewsPopup.Control.UI.Visible.DisallowedButton ? TEXT("true") : TEXT("false"));
     OnLog("- NewsPopup.Control.UI.Visible.ForwardButton :%s", NewsPopup.Control.UI.Visible.ForwardButton ? TEXT("true") : TEXT("false"));
     OnLog("- NewsPopup.Control.UI.Visible.HomeButton :%s", NewsPopup.Control.UI.Visible.HomeButton ? TEXT("true") : TEXT("false"));
     OnLog("- NewsPopup.Control.UI.Visible.NavigationBar :%s", NewsPopup.Control.UI.Visible.NavigationBar ? TEXT("true") : TEXT("false"));
     OnLog("- NewsPopup.Control.UI.Visible.RefreshButton :%s", NewsPopup.Control.UI.Visible.RefreshButton ? TEXT("true") : TEXT("false"));
 
     OnLog("- NewsPopup.Control.UI.CloseButtonImage.Normal.FileId :%s", *(NewsPopup.Control.UI.CloseButtonImage.Normal.FileId));
     OnLog("- NewsPopup.Control.UI.CloseButtonImage.Normal.FileUrl :%s", *(NewsPopup.Control.UI.CloseButtonImage.Normal.FileUrl));
     OnLog("- NewsPopup.Control.UI.CloseButtonImage.Pressed.FileId :%s", *(NewsPopup.Control.UI.CloseButtonImage.Pressed.FileId));
     OnLog("- NewsPopup.Control.UI.CloseButtonImage.Pressed.FileUrl :%s", *(NewsPopup.Control.UI.CloseButtonImage.Pressed.FileUrl));
 
     OnLog("- NewsPopup.Control.UI.CloseButtonImage.Type :%d", NewsPopup.Control.UI.CloseButtonImage.Type);
 
     OnLog("- RequestHeader size = %d", HeaderSize);
 
     for (int i = 0; i < HeaderSize; i++, Headers++)
     {
         OnLog(" - Header[%d].Name : %s", i, *(Headers->Name));
         OnLog(" - Header[%d].Value : %s", i, *(Headers->Value));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

Precautions

Even if the success callback (OnNewsPopup) is executed, NewsPopup callback parameter properties may be default values (empty string or 0).
You need to check the url property of the NewsPopup callback parameter before deciding whether to open a popup.
In this case, check the news pop-up settings of Partners.

If an error occurs while running the UMyStoveSDKObject::StoveSDKGetNewsPopup function, the UMyStoveSDKObject::OnError callback is called.
You can check external errors through the ExternalError field of the FStoveError structure.

ExternalError Description
403000 Invalid Access Error
400000 Wrong API usage Error
400001 Not Found Error
400002 Not Match Error
400003 Already exist
500001 Internal Interaction Error
900000 Unknown Service Error

# 6) Get coupon pop-up information

Search coupon popup information with UMyStoveSDKObject::StoveSDKGetCouponPopup function.

void UMyStoveSDKObject::OnCouponPopup(FStoveCouponPopup CouponPopup, int HeaderSize, FStovePopupRequestHeader* Headers)
{
     /*Add the 'walkthrough' codes here.*/

     OnLog("[CouponPopup]");

     OnLog("- CouponPopup.Url : %s", *(CouponPopup.Url));

     OnLog("- CouponPopup.Control.UI.DisallowedDay :%d", CouponPopup.Control.UI.DisallowedDay);

     OnLog("- CouponPopup.Control.UI.Visible.BackButton :%s", CouponPopup.Control.UI.Visible.BackButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.CloseButton :%s", CouponPopup.Control.UI.Visible.CloseButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.DisallowedButton :%s", CouponPopup.Control.UI.Visible.DisallowedButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.ForwardButton :%s", CouponPopup.Control.UI.Visible.ForwardButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.HomeButton :%s", CouponPopup.Control.UI.Visible.HomeButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.NavigationBar :%s", CouponPopup.Control.UI.Visible.NavigationBar ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.RefreshButton :%s", CouponPopup.Control.UI.Visible.RefreshButton ? TEXT("true") : TEXT("false"));

     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Normal.FileId :%s", *(CouponPopup.Control.UI.CloseButtonImage.Normal.FileId));
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Normal.FileUrl :%s", *(CouponPopup.Control.UI.CloseButtonImage.Normal.FileUrl));
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Pressed.FileId :%s", *(CouponPopup.Control.UI.CloseButtonImage.Pressed.FileId));
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Pressed.FileUrl :%s", *(CouponPopup.Control.UI.CloseButtonImage.Pressed.FileUrl));

     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Type :%d", CouponPopup.Control.UI.CloseButtonImage.Type);

     OnLog(" - RequestHeader size = %d", HeaderSize);

   
     for (int i = 0; i < HeaderSize; i++, Headers++)
     {
         OnLog(" - Header[%d].Name : %s", i, *(Headers->Name));
         OnLog(" - Header[%d].Value : %s", i, *(Headers→Value));

    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

When the UMyStoveSDKObject::StoveSDKGetCouponPopup function is successfully processed, the UMyStoveSDKObject::OnCouponPopup callback is called.
The FStoveCouponPopup structure passed to the callback contains the URL to the coupon popup.
The FStovePopupRequestHeader structure passed to the callback contains name/value pairs of headers to be set when requesting URLs.

void UMyStoveSDKObject::OnCouponPopup(FStoveCouponPopup CouponPopup, int HeaderSize, FStovePopupRequestHeader* Headers)
{
     /*Add the 'walkthrough' codes here.*/ OnLog("[CouponPopup]");
 
     OnLog("- CouponPopup.Url : %s", *(CouponPopup.Url));
 
     OnLog("- CouponPopup.Control.UI.DisallowedDay :%d", CouponPopup.Control.UI.DisallowedDay);
 
     OnLog("- CouponPopup.Control.UI.Visible.BackButton :%s", CouponPopup.Control.UI.Visible.BackButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.CloseButton :%s", CouponPopup.Control.UI.Visible.CloseButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.DisallowedButton :%s", CouponPopup.Control.UI.Visible.DisallowedButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.ForwardButton :%s", CouponPopup.Control.UI.Visible.ForwardButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.HomeButton :%s", CouponPopup.Control.UI.Visible.HomeButton ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.NavigationBar :%s", CouponPopup.Control.UI.Visible.NavigationBar ? TEXT("true") : TEXT("false"));
     OnLog("- CouponPopup.Control.UI.Visible.RefreshButton :%s", CouponPopup.Control.UI.Visible.RefreshButton ? TEXT("true") : TEXT("false"));
 
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Normal.FileId :%s", *(CouponPopup.Control.UI.CloseButtonImage.Normal.FileId));
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Normal.FileUrl :%s", *(CouponPopup.Control.UI.CloseButtonImage.Normal.FileUrl));
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Pressed.FileId :%s", *(CouponPopup.Control.UI.CloseButtonImage.Pressed.FileId));
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Pressed.FileUrl :%s", *(CouponPopup.Control.UI.CloseButtonImage.Pressed.FileUrl));
 
     OnLog("- CouponPopup.Control.UI.CloseButtonImage.Type :%d", CouponPopup.Control.UI.CloseButtonImage.Type);
 
     OnLog(" - RequestHeader size = %d", HeaderSize);
     
     for (int i = 0; i < HeaderSize; i++, Headers++)
     {
         OnLog(" - Header[%d].name : %s", i, *(Headers->Name));
         OnLog(" - Header[%d].value : %s", i, *(Headers->Value));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

If an error occurs while running the UStoveSDKObject::StoveSDKGetCouponPopup function, the UStoveSDKObject::OnError callback is called.

# 7) Get community pop-up information

Use the UMyStoveSDKObject::StoveSDKGetCommunityPopup function to query community popup information.

FStoveResult UMyStoveSDKObject::StoveSDKGetCommunityPopup()
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKGetCommunityPopup();
     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {

          // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13

When the UMyStoveSDKObject::StoveSDKGetCommunityPopup function is successfully processed, the UStoveSDKObject::OnCommunityPopup callback is called.
The FStoveCommunityPopup structure passed to the callback contains the URL to the community popup.
The FStovePopupRequestCookie structure passed to the callback contains the cookie name/value pair to be set when requesting the URL.

void UMyStoveSDKObject::OnCommunityPopup(FStoveCommunityPopup CommunityPopup, int CookieSize, FStovePopupRequestCookie* Cookies)
{
     OnLog("[CommunityPopup]");
 
     OnLog("- CommunityPopup.Url : %s", *(CommunityPopup.Url));
 
     OnLog("- CommunityPopup.Control.UI.DisallowedDay :%d", CommunityPopup.Control.UI.DisallowedDay);
 
     OnLog("- CommunityPopup.Control.UI.Visible.BackButton :%s", CommunityPopup.Control.UI.Visible.BackButton ? TEXT("true") : TEXT("false"));
     OnLog("- CommunityPopup.Control.UI.Visible.CloseButton :%s", CommunityPopup.Control.UI.Visible.CloseButton ? TEXT("true") : TEXT("false"));
     OnLog("- CommunityPopup.Control.UI.Visible.DisallowedButton :%s", CommunityPopup.Control.UI.Visible.DisallowedButton ? TEXT("true") : TEXT("false"));
     OnLog("- CommunityPopup.Control.UI.Visible.ForwardButton :%s", CommunityPopup.Control.UI.Visible.ForwardButton ? TEXT("true") : TEXT("false"));
     OnLog("- CommunityPopup.Control.UI.Visible.HomeButton :%s", CommunityPopup.Control.UI.Visible.HomeButton ? TEXT("true") : TEXT("false"));
     OnLog("- CommunityPopup.Control.UI.Visible.NavigationBar :%s", CommunityPopup.Control.UI.Visible.NavigationBar ? TEXT("true") : TEXT("false"));
     OnLog("- CommunityPopup.Control.UI.Visible.RefreshButton :%s", CommunityPopup.Control.UI.Visible.RefreshButton ? TEXT("true") : TEXT("false"));
 
     OnLog("- CommunityPopup.Control.UI.CloseButtonImage.Normal.FileId :%s", *(CommunityPopup.Control.UI.CloseButtonImage.Normal.FileId));
     OnLog("- CommunityPopup.Control.UI.CloseButtonImage.Normal.FileUrl :%s", *(CommunityPopup.Control.UI.CloseButtonImage.Normal.FileUrl));
     OnLog("- CommunityPopup.Control.UI.CloseButtonImage.Pressed.FileId :%s", *(CommunityPopup.Control.UI.CloseButtonImage.Pressed.FileId));
     OnLog("- CommunityPopup.Control.UI.CloseButtonImage.Pressed.FileUrl :%s", *(CommunityPopup.Control.UI.CloseButtonImage.Pressed.FileUrl));
 
     OnLog("- CommunityPopup.Control.UI.CloseButtonImage.Type :%d", CommunityPopup.Control.UI.CloseButtonImage.Type);
 
     OnLog("- RequestCookie size = %d", CookieSize);
     
     for (int i = 0; i < CookieSize; i++, Cookies++)
     {
         OnLog(" - Cookie[%d].Name : %s", i, *(Cookies->Name));
         OnLog(" - Cookie[%d].Value : %s", i, *(Cookies->Value));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

If an error occurs while running the UMyStoveSDKObject::StoveSDKGetCommunityPopup function, the UStoveSDKObject::OnError callback is called.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
13008 Mandatory Parameter missing
90001 AccessToken invalid
40101 Invalid token

# 8) Disable pop-ups 2.6.0

With the UMyStoveSDKObject::StoveSDKSetPopupDisallowed function, set a specific pop-up not to be displayed for a certain period of time.
If the game directly implements the PC SDK pop-up UI, configure the UI by referring to the Control.UI.Visible.DisallowedButton value of the pop-up UI information
Call the UMyStoveSDKObject::StoveSDKSetPopupDisallowed function in the button click handler.
When calling the UMyStoveSDKObject::StoveSDKSetPopupDisallowed function, the days parameter uses the Control.UI.DisallowedDay value of the popup information.
If pop-up disallow is set, the relevant pop-up information will not be searched during the disallow period.

// input parameters
// const int PopupId : Popup identifier issued by Partners
//const int Days : the number of days that Partners has registered as unavailable (once) or -1 (don't look again)
// const int Days : Unacceptable period registered by Partners (in days)

FStoveResult UMyStoveSDKObject::StoveSDKSetPopupDisallowed(const int PopupId, const int Days)
{
     /*Add the 'walkthrough' codes here.*/
     FStoveResult ErrorResult = Super::StoveSDKSetPopupDisallowed(PopupId, Days);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# Integrate billing 2.6.0

The PC SDK provides APIs to integrate Stove Platform's billing service into games. There is a shop as a billing service.
A typical scenario for a store is below. This may vary slightly depending on the game situation (e.g. whether or not there is a game server).

  • Information for store configuration is acquired through store category search and product search APIs.
  • The game organizes the store through the acquired category and product information and displays the UI.
  • Purchases for each product call the purchase start API to obtain a one-time payment URL.
    • In the case of a product with a selling price of 0
      • The purchase is completed when the purchase start API response is received.
    • For products with a selling price greater than 0
      • Obtain the one-time payment URL from the response of the purchase start API.
      • The game browses the one-time payment URL with an external browser. Supported browsers: Chrome (75+), Edge (42+)
      • Subsequent payment process will be completed through the web page.
  • When the payment is complete, the game calls the Purchase Status Check API to check the purchase status.
  • If the payment is confirmed to have been completed normally, the game will provide the product.
  • You can check the product purchase history (whether purchased more than once) through the purchase verification API.
  • It can be used to restore items through the library inquiry API.

In order to use the PC SDK billing service API, you must register the metadata of the billing service through Partners in advance.
Also, if you use the store through the PC SDK, you must call the UMyStoveSDKObject::StoveSDKIAPInit function and pass the ShopKey issued from the partners.
An error will be returned if the billing service API is called without ShopKey settings.

The game must check whether you agree to the terms of service every time you open the store.
If the game user does not agree to the service terms and conditions, open the browser using the terms and conditions agreement page URL provided by PCSDK so that the game user can agree to the service terms and conditions.
When a game user agrees to the terms of service and opens the store, he or she enters the store.

PC SDK operates internal cache for store support.

Using the isRefresh parameter of the UMyStoveSDKObject::StoveSDKFetchProducts function, you can determine whether to retrieve product information from the cache or via Web API.
The product information retrieved through the Web API is updated in whole or in part (by category) in the cache, and then the product information is passed to the game as a callback.
(However, if the cache is empty, the product information is retrieved through the Web API and updated to the cache regardless of the value of the isRefresh parameter.)
In addition, the PC SDK updates the purchase/sale quantity and purchase status of each product in the cache through the Web API response at the time of calling the UMyStoveObject::StoveSDKConfirmPurchase function.

# (Example) Flow chart of billing integration

confirm confirm

  1. Initialize PC_SDK when starting the game
    • Initialize IAP through UMyStoveSDKObject::StoveSDKIAPInit function.
    • When IAP is initialized, the entire item list is retrieved and stored in the built-in cache.
  2. Handling non-payment inquiries when entering the in-game shop page (optional)
    • If there are unpaid items after completing payment through UMyStoveSDKObject::StoveSDKFetchInventory storage check, re-supply is processed.
  3. After entering the store, search the category list for store composition.
    • Search categories in the store through UMyStoveSDKObject::StoveSDKFetchShopCategories function.
  4. Search the item information through the category information in the store inquired in number 3.
    • Search product information included in the category through UMyStoveSDKObject::StoveSDKFetchProducts function.
  5. Select an item to purchase from the store.
    • Purchase product information must be composed directly in an array. (ProductId/SalePrice/Quantity)
    • Quantity must be specified as 1.
  6. Search for one-time payment URL information to start product purchase.
    • Search the one-time payment window URL information through UMyStoveSDKObject::StoveSDKStartPurchase function.
  7. Process the product payment information pop-up within the game. (It must be processed to check the payment result in an external browser.)
  8. Pop up an external browser with the one-time payment URL information obtained through step 6.
  9. Proceed with product payment through the payment window of Stove billing.
    • Close the browser after payment is completed in the payment window.
  10. When you click the "Payment Complete" button on the product payment information pop-up created in step 7 in-game, the purchase status information is searched.
  • Search information on the payment status through UMyStoveSDKObject::StoveSDKConfirmPurchase function.
  • After checking the payment completion status, close the pop-up and return to the store page.
  1. The purchase flow is complete.

reference

Stove payment is not in progress through an external browser and the payment result is not known through UMyStoveSDKObject::StoveSDKStartPurchase
When entering the store page (2 times), the item is re-issued through UMyStoveSDKObject::StoveSDKFetchInventory inventory inquiry.


The sequence diagram below shows a hypothetical store operation scenario.
This is an example of a general case and may differ slightly depending on the game situation (e.g. store category structure, store UI creation time, etc.).

  • PCSDK IAP initialization
  • Check to accept the Terms of Service
  • Open shop
  • Purchase goods
  • Check product purchase status
  • Verification of product purchase history
  • Handle item restoration

# 1) Callback setting

In order to communicate with the PC SDK using the billing service API, the game must override the callback function defined in the UMyStoveSDKObject class below.

//StoveCallback

UCLASS()
class HELLOSTOVE_API UMyStoveSDKObject : public UStoveSDKObject
{
     GENERATED_BODY()

public:

     void OnInitComplete() final;
     void OnError(FStoveError Error) final;
     void OnToken(FStoveToken Token) final;
     void OnUser(FStoveUser User) final;
     void OnOwnership(int Size, FStoveOwnership* Ownerships) final;

     // Callback called when FetchShopCategories processing is complete
     void OnFetchShopCategories(int Size, FStoveShopCategories* Categories) final;

     // Callback called when FetchProducts processing is complete
     void OnFetchProducts(int Size, FStoveProduct* Products) final;

     // Callback called when StartPurchase processing is complete
     void OnStartPurchase(FStovePurchase Purchase) final;

     // Callback called when ConfirmPurchase processing is complete
     void OnConfirmPurchase(int Size, FStovePurchaseProduct* PurchaseProducts, bool Status, FString ShopKey) final;

     // Callback called when FetchInventory processing is complete
     void OnFetchInventory(int Size, FStoveInventoryItem* InventoryItems) final;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

As in ‘Interlocking 2) Config, Callback setting’, override the callback function to receive the event.

// billing service
void UMyStoveSDKObject::OnFetchTermsAgreement(const FStoveTermsAgreement TermsAgreement)
{
   // Terms of Service
}
void UMyStoveSDKObject::OnFetchShopCategories(int Size, FStoveShopCategories* Categories)
{
    // After calling the store category API
}

void UMyStoveSDKObject::OnFetchProducts(int Size, FStoveProduct* Products)
{
    // After calling the product API registered in the store
}
void UMyStoveSDKObject::OnStartPurchase(FStovePurchase Purchase)
{
    // After trying to pay for the product
}
void UMyStoveSDKObject::OnConfirmPurchase(int Size, FStovePurchaseProduct* PurchaseProducts, bool Status, FString ShopKey)
{
    // after product purchase confirmation
}
void UMyStoveSDKObject::OnFetchInventory(int Size, FStoveInventoryItem* InventoryItems)
{
    // After calling the archive search API
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

You are not required to implement the OnFetchTermsAgreement, OnFetchShopCategories, OnFetchProducts, OnStartPurchase, OnConfirmPurchase, OnFetchInventory callbacks.
You only need to connect the store when the game needs it. However, for the store function, all 5 callbacks must be implemented and connected.

# 2) Initialize IAP

If the game decides to use PCSDK to provide billing service, try initializing billing with the UMyStoveSDKObject::StoveSDKIAPInit function with the ShopKey factor value of the store key issued by the stove.
When billing initialization is attempted, the product list registered on the Stove platform is automatically retrieved and stored in the Stove PCSDK internal cache.
Call the UMyStoveSDKObject::StoveSDKIAPInit function, and if it fails, send the error details to the FStoveResult and OnError callbacks.

// input parameters
// FString ShopKey: ShopKey issued by the stove

FStoveResult UMyStoveSDKObject::StoveSDKIAPInit(const FString& ShopKey)
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKIAPInit(ShopKey);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
        // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ExternalError Description
500 Internal Server Error
50001 Store does not exist, or is under maintenance
50002 Product does not exist or is unavailable for sale
999999 undefined error

# 3) Game profile settings

Set game world and character information with UMyStoveSDKObject::StoveSDKSetGameProfile function.
This is to determine the level of the product purchasing entity. The PC SDK prioritizes the purchaser of the product as follows.

  • Character No. > Guid > Member No.

When character information is set through UMyStoveSDKObject::StoveSDKSetGameProfile function, PC SDK proceeds with purchase based on Character No. when purchasing a product.
On the other hand, if character information is not set through UMyStoveSDKObject::StoveSDKSetGameProfile function, PC SDK proceeds with purchase based on Guid or Member No.
Therefore, in order to ensure that the purchasing subject is properly applied when purchasing a product, you should consider whether to call the UMyStoveSDKObject::StoveSDKSetGameProfile API before calling the PC SDK billing service API.
Normally, UMyStoveSDKObject::StoveSDKSetGameProfile function only needs to be called once per world/character change.

# 4) Get store category information

Use the UMyStoveSDKObject::StoveSDKFetchShopCategories function to retrieve store category information for the game.
Category information includes the ID of the parent category, so you can organize your store in a hierarchical structure.

FStoveResult UMyStoveSDKObject::StoveSDKFetchShopCategories()
{
     FStoveResult ErrorResult = Super::StoveSDKFetchShopCategories();
     if(ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // Success processing
     }

    return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10

If the UMyStoveSDKObject::StoveSDKFetchShopCategories function is processed successfully, the OnFetchShopCategories callback is called.
The FStoveShopCategory structure passed to the callback contains meta information about the store category.

  • FStoveShopCategory.CategoryId: Category ID
  • FStoveShopCategory.ParentCategoryId: Parent category ID
  • FStoveShopCategory.DisplayNo: Category order
  • FStoveShopCategory.Name: Category name
  • FStoveShopCategory.Depth: Category depth (1 for top level category)
void UMyStoveSDKObject::OnFetchShopCategories(int Size, FStoveShopCategories* Categories)
{

     /*Add the 'walkthrough' codes here.*/
   
     OnLog("[OnFetchShopCategories]");
     OnLog("ShopCategories size = %d ", Size);

     for (int i = 0; i < Size; i++, Categories++)
     {
         OnLog(" -> Index: %d", i);
         OnLog("-------------------------------------------------------------- --------");
         OnLog(" CategoryId : %s", *(Categories->CategoryId));
         OnLog(" ParentCategoryId : %s", *(Categories->ParentCategoryId));
         OnLog(" DisplayNo : %d", Categories->DisplayNo);
         OnLog(" Name : %s", *(Categories->Name));
         OnLog(" Depth : %d", Categories->Depth);
         OnLog("-------------------------------------------------------------- --------");
     }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

If an error occurs during execution of the UMyStoveSDKObejct::StoveSDKFetchShopProducts function, the OnError callback is called.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
500 Internal Server Error
999999 undefined error

# 5) Get store category information

Use the UMyStoveSDKObject::StoveSDKFetchShopCategories function to retrieve store category information for the game.
Category information includes the ID of the parent category, so you can organize your store in a hierarchical structure.

FStoveResult UMyStoveSDKObject::StoveSDKFetchShopCategories()
{
     FStoveResult ErrorResult = Super::StoveSDKFetchShopCategories(StatId, StatValue);
     if(ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // handle success
     }

    return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10

When the UMyStoveSDKObject::StoveSDKFetchShopCategories function is successfully processed, the OnFetchShopCategories callback is called.
The FStoveShopCategory structure passed to the callback contains meta information about the store category.

  • FStoveShopCategory.CategoryId : Category ID
  • FStoveShopCategory.ParentCategoryId: Parent category ID
  • FStoveShopCategory.DisplayNo: Category order
  • FStoveShopCategory.Name: category name
  • FStoveShopCategory.Depth: category depth (1 for top level category)
void UMyStoveSDKObject::OnFetchShopCategories(int Size, FStoveShopCategories* Categories)
{

     /*Add the 'walkthrough' codes here.*/
   
     OnLog("[OnFetchShopCategories]");
     OnLog("ShopCategories size = %d ", Size);

     for (int i = 0; i < Size; i++, Categories++)
     {
         OnLog(" -> Index: %d", i);
         OnLog("---------------------------------------------- --------");
         OnLog(" CategoryId : %s", *(Categories->CategoryId));
         OnLog(" ParentCategoryId : %s", *(Categories->ParentCategoryId));
         OnLog(" DisplayNo : %d", Categories->DisplayNo);
         OnLog(" Name : %s", *(Categories->Name));
         OnLog(" Depth : %d", Categories->Depth);
         OnLog("---------------------------------------------- --------");
     }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

The OnError callback is called if an error occurs while running the UMyStoveSDKObejct::StoveSDKFetchShopProducts function.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
500 Internal Server Error
999999 undefined error

# 6) Get product information

Search product information for the game with UMyStoveSDKObject::StoveSDKFetchProducts function.

// input parameters
// FString CategoryId: Category identifier registered by Partners (search all categories when passing an empty string)
// bool IsRefresh : If true, search Web API, if false, search PC SDK Cache

FStoveResult UMyStoveSDKObject::StoveSDKFetchProducts(const FString& CategoryId, const bool IsRefresh)
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKFetchProducts(CategoryId, IsRefresh);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

When the UMyStoveSDKObject::StoveSDKFetchProducts function is successfully processed, the OnFetchProducts callback is called.
The FStoveProduct structure passed to the callback contains meta information about the product.

  • FStoveProduct.ProductId: Product ID
  • FStoveProduct.GameItemId: In-game item ID mapped to product ID
  • FStoveProduct.Name : product name
  • FStoveProduct.Description : product description
  • FStoveProduct.Quantity: Quantity of each product
  • FStoveProduct.ProductTypeCode : Product type code (1: game product, 2: in-game product, 3: package item)
  • FStoveProduct.CategoryId : Category ID
  • FStoveProduct.CurrencyCode : Currency code
  • FStoveProduct.Price: List price of the product (when displaying, if the CurrencyCode is equal to "KRW", the decimal point is omitted; if it is different, the second decimal place is indicated)
  • FStoveProduct.SalePrice: Product sales price (when displaying, if the CurrencyCode is equal to "KRW", the decimal point is omitted; if it is different, it is indicated to the second decimal place)
  • FStoveProduct.IsDiscount: Whether discount
  • FStoveProduct.DiscountType: Discount type (1: flat rate, 2: flat rate)
  • FStoveProduct.DiscountTypeValue: discount value
  • FStoveProduct.DiscountBeginDate : Discount start date (UTC+0)
  • FStoveProduct.DiscountEndDate : Discount end date (UTC+0)
  • FStoveProduct.TotalQuantity: total sales quantity of the product
  • FStoveProduct.MemberQuantity: Member purchase quantity
  • FStoveProduct.GuidQuantity: Guid purchase quantity (purchase quantity of product purchase subject [CharacterNo/Guid/MemberNo])
  • FStoveProduct.ThumbnailUrl : Representative product image
void UMyStoveSDKObject::OnFetchProducts(int Size, FStoveProduct* Products)
{
      /*Add the 'walkthrough' codes here.*/

     OnLog("[OnFetchProducts]");

     OnLog("Products Size = %d ", Size);

     FString Builder;

     for (int i = 0; i < Size; i++, Products++)
     {
         Builder.Append(FString::Printf(TEXT("-> Index : %d\n"), i));
         Builder.Append(FString::Printf(TEXT("-------------------------------------- -----------------\n")));
         Builder.Append(FString::Printf(TEXT(" ProductId : %I64d\n"), Products->ProductId));
         Builder.Append(FString::Printf(TEXT(" GameItemId : %s\n"), *(Products->GameItemId)));
         Builder.Append(FString::Printf(TEXT(" Name : %s\n"), *(Products->Name)));
         Builder.Append(FString::Printf(TEXT(" Description : %s\n"), *(Products->Description)));
         Builder.Append(FString::Printf(TEXT(" Quantity : %d\n"), Products->Quantity));
         Builder.Append(FString::Printf(TEXT(" ProductTypeCode : %hd\n"), Products->ProductTypeCode));
         Builder.Append(FString::Printf(TEXT(" CategoryId : %s\n"), *(Products->CategoryId)));
         Builder.Append(FString::Printf(TEXT(" CurrencyCode : %s\n"), *(Products->CurrencyCode)));
         if (Products->CurrencyCode.Compare(TEXT("KRW"), ESearchCase::IgnoreCase) == 0)
         {
             Builder.Append(FString::Printf(TEXT(" Price : %.0lf\n"), Products->Price));
             Builder.Append(FString::Printf(TEXT(" SalePrice : %.0lf\n"), Products->SalePrice));
         }
         else
         {
             Builder.Append(FString::Printf(TEXT(" Price : %.2lf\n"), Products->Price));
             Builder.Append(FString::Printf(TEXT(" SalePrice : %.2lf\n"), Products->SalePrice));
         }
         Builder.Append(FString::Printf(TEXT(" IsDiscount : %s\n"), Products->bIsDiscount ? TEXT("true") : TEXT("false")));
         Builder.Append(FString::Printf(TEXT(" DiscountType : %hd\n"), Products->DiscountType));
         Builder.Append(FString::Printf(TEXT(" DiscountTypeValue : %d\n"), Products->DiscountTypeValue));
         Builder.Append(FString::Printf(TEXT(" DiscountBeginDate : %I64d\n"), Products->DiscountBeginDate));
         Builder.Append(FString::Printf(TEXT(" DiscountEndDate : %I64d\n"), Products->DiscountEndDate));
         Builder.Append(FString::Printf(TEXT(" TotalQuantity : %d\n"), Products->TotalQuantity));
         Builder.Append(FString::Printf(TEXT(" MemberQuantity : %d\n"), Products->MemberQuantity));
         Builder.Append(FString::Printf(TEXT(" GuidQuantity : %d\n"), Products->GuidQuantity));
         Builder.Append(FString::Printf(TEXT(" ThumbnailUrl : %s\n"), *(Products->ThumbnailUrl)));
         Builder.Append(FString::Printf(TEXT(" CanWithdraw : %s\n"), Products->bCanWithdraw ? TEXT("true") : TEXT("false")));
         Builder.Append(FString::Printf(TEXT("-------------------------------------- -----------------\n")));
     }

     OnLog("%s", *Builder);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

The OnError callback is called if an error occurs while running the UMyStoveSDKObject::StoveSDKFetchProducts function.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
500 Internal Server Error
50001 Store does not exist, or is under maintenance
50002 Product does not exist or is unavailable for sale
999999 undefined error

# 7) Start purchasing products

Start product purchase with UMyStoveSDKObject::StoveSDKStartPurchase function.

// input parameters
// const TArray<FStoveOrderProduct> Products: Order product information
// ProductSize: number of ordered products

FStoveResult UMyStoveSDKObject::StoveSDKStartPurchase(const TArray<FStoveOrderProduct> Products, const int ProductSize)
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKStartPurchase(Products, ProductSize);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

When the UMyStoveSDKObject::StoveSDKStartPurchase function is successfully processed, the OnStartPurchase callback is called.
The FStovePurchase structure passed to the callback contains meta information about product purchase.

  • FStovePurchase.TransactionMasterNo: Transaction unique master number
  • FStovePurchase.TempPaymentUrl : One-time payment URL
  • FStovePurchase.PurchaseProgress : Purchase progress status
    • 1: Payment in progress (page displayed in external browser)
    • 2: Purchase completed (Payment is completed due to the purchase of a product with a selling price of 0, so it is not necessary to display the page in an external browser using TempPaymentUrl)

When necessary, the game browses the one-time payment URL through an external browser. Supported browsers: Chrome (75+), Edge (42+)

void UMyStoveSDKObject::OnStartPurchase(FStovePurchase Purchase)
{
     /*Add the 'walkthrough' codes here.*/
     OnLog("[OnStartPurchase]");

     OnLog(" TransactionMasterNo : %I64d", Purchase.TransactionMasterNo);
     OnLog(" TempPaymentUrl : %s", *(Purchase. TempPaymentUrl));
     OnLog(" PurchaseProgress : %d", Purchase. PurchaseProgress);

     if (Purchase. PurchaseProgress == 1)
     {
         FWindowsPlatformProcess::LaunchURL(*(Purchase. TempPaymentUrl), nullptr, nullptr);
     }
     else if(Purchase. PurchaseProgress == 2)
     {
         //Process purchase completion (e.g. purchase completion message box)
      }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

The OnError callback is called if an error occurs while the UMyStoveSDKObject::StoveSDKStartPurchase' function is running.
External errors can be checked through the ExternalError field of the FStoveError structure.
Normally, when the OnError callback is called for the UMyStoveSDKObject::StoveSDKStartPurchase function call, the game exposes a message about the failure to the game user.
The table below provides a guide on what messages to display to game users.

| ExternalError | Description | Check the exposure message for game users | |:-------------|:-----------------------------|:- ------------------------------------| | 500 | Internal Server Error | This is a temporary phenomenon or the service is not smooth due to network reasons. | | 50001 | Store does not exist, or is under maintenance | The service is under maintenance, or the service does not exist. | | 50002 | Product does not exist or is unavailable for sale | This product cannot be purchased due to its condition. | | 50003 | non-exhibition products | This product is not currently on sale. | | 50004 | Products outside the sale period | This is not a product sale period. | | 50005 | Product price inconsistency (if product price is changed) | Product price information has been changed. | | 50009 | Exceeds the number of sales per member that can be purchased | The number of purchases per person has been exceeded. | | 50010 | Exceeds the total number of sales available for purchase | All prepared quantities have been sold. | | 50031 | Purchase quantity is '0' | Please enter at least one quantity to purchase. | | 999999 | undefined error | The service is not smooth due to other errors.

# 8) Check product purchase status

Check the product purchase status with UMyStoveSDKObject::StoveSDKConfirmPurchase function.

// input parameters
// FString TransactionMasterNo : Unique transaction master number (obtained through OnStartPurchase callback parameter FStovePCPurchase.transactionMasterNo)

FStoveResult UMyStoveSDKObject::StoveSDKConfirmPurchase(const FString& TransactionMasterNo)
{
     /*Add the 'walkthrough' codes here.*/

     FStoveResult ErrorResult = Super::StoveSDKConfirmPurchase(TransactionMasterNo);

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         // handle success
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

When the UMyStoveSDKObject::StoveSDKConfirmPurchase function is successfully processed, the OnConfirmPurchase callback is called.
The FStovePurchaseProduct structure passed to the callback contains meta information about the purchased product, and the status callback parameter delivers the product purchase status.

  • FStovePurchaseProduct.TotalQuantity: Total product sales quantity
  • FStovePurchaseProduct.MemberQuantity : Member purchase quantity
  • FStovePurchaseProduct.GuidQuantity: Guid purchase quantity (purchase quantity of product purchase subject [CharacterNo/Guid/MemberNo])

In the case of a game without a separate game server, if the purchase result is successful, the game may provide an item.
In the case of a game with a game server, the game server can receive a notification about the purchase and can provide the item at this time.

void UMyStoveSDKObject::OnConfirmPurchase(int Size, FStovePurchaseProduct* PurchaseProducts, bool Status, FString ShopKey)
{
     /*Add the 'walkthrough' codes here.*/

     OnLog("[OnConfirmPurchase]");

     OnLog(" Status : %s", Status ? TEXT("true") : TEXT("false"));
     OnLog(" ShopKey : %s", *(ShopKey));
     OnLog(" PurchaseProduct size : %d", Size);

     for (int i = 0; i < Size; i++, PurchaseProducts++)
     {
         OnLog(" -> Index: %d", i);
         OnLog("---------------------------------------------- --------");
         OnLog(" CategoryId : %s", *(PurchaseProducts->CategoryId));
         OnLog(" ProductId : %I64d", PurchaseProducts->ProductId);
         OnLog(" TotalQuantity : %d", PurchaseProducts->TotalQuantity);
         OnLog(" MemberQuantity : %d", PurchaseProducts->MemberQuantity);
         OnLog(" GuidQuantity : %d", PurchaseProducts->GuidQuantity);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

reference

In the above sample code, FString shopKey in the function is the same value as YOUR_SHOP_KEY called by StoveSDKIAPInit function.

You need to send YOUR_SHOP_KEY with shopKey as an input parameter.

If an error occurs while executing UMyStoveSDKObject::OnConfirmPurchase function, OnError callback will be called.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
500 Internal Server Error
999999 undefined error

# 9) Verification of product purchase history

Use the UMyStoveSDKObject::StoveSDKVerifyPurchase function to verify product purchase history.
The value of the IsPurchased field is true for products that have been purchased more than once.
Verification of product purchase history is performed targeting the cache within the PC SDK.
At this time, if you explicitly enter the value of the CategoryId parameter, only that category will be searched.
If you enter an empty string ("") in the value of the CategoryId parameter, the search will be conducted for all categories.
Therefore, it may be advantageous in terms of search speed to accurately enter the category ID to search.

// input parameters
// const FString& CategoryId: Category ID to search for products
// const FString& ProductId : Product ID

const FStovePurchaseVerification UMyStoveSDKObject::StoveSDKVerifyPurchase(const FString& CategoryId, const FString& ProductId)
{
      /*Add the 'walkthrough' codes here.*/
    
     FStovePurchaseVerification Verify = Super::StoveSDKVerifyPurchase(CategoryId, ProductId);

     if (Verify.ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
         OnLog("[Success] StoveSDKVerifyPurchase");
         OnLog("%s product in %s category was %s", *ProductId, *CategoryId, Verify.IsPurchased ? TEXT("purchased") : TEXT("not purchased"));
     }
     else
     {
         //failure handling
     }

     return Verify;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

The UMyStoveSDKObject::StoveSDKVerifyPurchase function returns a FStovePurchaseVerification structure.
The returned FStovePurchaseVerification structure contains the product purchase history.
Also, error codes for function calls are included.

# 10) Search archives

Use the UMyStoveSDKObject::StoveSDKFetchInventory function to retrieve the inventory.
Items that have been purchased are stored in the storage box.
You can process product payment by using the list of purchased products in the storage box.
Normally, games call the UMyStoveSDKObject::StoveSDKFetchInventory function to check the product purchase status and immediately deliver the product.
If the product information provided is lost due to an error, game reinstallation, etc., it can be used for recovery work using the storage box information.

FStoveResult UMyStoveSDKObject::StoveSDKFetchInventory()
{
     /*Add the 'walkthrough' codes here.*/
     FStoveResult ErrorResult = Super::StoveSDKFetchInventory();

     if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
     {
        // success handling
     }

     return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12

When the UMyStoveSDKObject::StoveSDKFetchInventory function is successfully processed, the OnFetchInventory callback is called.
The FStoveInventoryItem structure passed to the callback contains meta information about the purchased product.

  • FStoveInventoryItem.TransactionMasterNo: Transaction unique master number
  • FStoveInventoryItem.TransactionDetailNo: transaction specific detail number
  • FStoveInventoryItem.ProductId: Product ID
  • FStoveInventoryItem.GameItemId: In-game item ID mapped to product ID
  • FStoveInventoryItem.ProductName: product name
  • FStoveInventoryItem.Quantity: Quantity of individual product
  • FStoveInventoryItem.ThumbnailUrl: Representative product image
void UMyStoveSDKObject::OnFetchInventory(int Size, FStoveInventoryItem* InventoryItems)
{
     /*Add the 'walkthrough' codes here.*/
     OnLog("[OnFetchInventory]");

     OnLog("InventoyItem size : %d", Size);

     for (int i = 0; i < Size; i++, InventoryItems++)
     {
         OnLog(" -> Index: %d", i);
         OnLog("---------------------------------------------- --------");
         OnLog(" TransactionMasterNo : %I64d", InventoryItems->TransactionMasterNo);
         OnLog(" TransactionDetailNo : %I64d", InventoryItems->TransactionDetailNo);
         OnLog(" ProductId : %I64d", InventoryItems->ProductId);
         OnLog(" GameItemId : %s", *(InventoryItems->GameItemId));
         OnLog(" ProductName : %s", *(InventoryItems->ProductName));
         OnLog(" Quantity : %d", InventoryItems->Quantity);
         OnLog(" ThumnailUrl : %s", *(InventoryItems->ThumbnailUrl));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

If an error occurs while executing UMyStoveSDKObject::StoveSDKFetchInventory function, OnError callback will be called.
External errors can be checked through the ExternalError field of the FStoveError structure.

ExternalError Description
500 Internal Server Error
999999 undefined error

# Integrating additional services

The PC SDK provides APIs to integrate additional services into games.
Additional services supported by PC SDK include custom event log, PC SDK version inquiry, over-immersion prevention notification, shutdown notification, tracking clue inquiry.
Games can send custom in-game events (game logs) to the Stove platform. Also, the game can query the semantic version of the PC SDK currently in use.
PC SDK semantic version inquiry can be obtained as a return value, not a callback.
The Over Immersion Prevention Alert delivers a warning phrase about over immersion in the game through a callback every hour.
Shutdown notification is a system that restricts children under the age of 18 from using the game at a specific time per day of the week by parents. When the requirements are met, notifications are delivered through callbacks up to 4 times.

# 1) Callback setting

In order to communicate with the PC SDK using the additional service API, the game must redefine the callback function connected to the UMyStovePCSDKObject class below.

UCLASS()
class HELLOSTOVE_API UMyStoveSDKObject : public UStoveSDKObject
{
    GENERATED_BODY()
public:

     //StovePCSDK Event
     void OnInitComplete() final;
     void OnError(FStoveError Error) final;
     void OnToken(FStoveToken Token) final;
     void OnUser(FStoveUser User) final;
     void OnOwnership(int Size, FStoveOwnership* Ownerships) final;
    
    
     //Callback called when StashCustomEvent processing is complete
     void OnStashCustomEvent(FStoveCustomEvent CustomEvent, int ParameterSize, FStoveCustomEventParameter* Parameters) final;
    
     // ADD 2.6.0 Start
     // Callback that is called every hour to prevent over-immersion
     void OnOverImmersion(FStoveOverImmersion OverImmersion) final;
    
     // Callback to be called on shutdown limit
     void OnShutdown(FStoveShutdown Shutdown) final;
     // 2.6.0 End

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

Link events by overriding the callback function of the 'UMyStoveSDKObject' class inherited from 'UStoveSDKObject' as in Connection 1) Config, Callback Settings.

/* In the case of using only the Ownership function,
In addition to the mandatory implementation callbacks OnError and OnInitComplete
Connect by implementing an additional OnOwnership callback.*/
void UMyStoveSDKObject::OnInitComplete()
{
       // Process contents after successful initialization
}
 
void UMyStoveSDKObject::OnError(FStoveError Error)
{
       // handling of errors
}
 
void UMyStoveSDKObject::OnOwnership(int Size, FStoveOwnership* Ownerships)
{
        // Process details after checking ownership
}
void UMyStoveSDKObject::OnStashCustomEvent(FStoveCustomEvent CustomEvent, int ParameterSize, FStoveCustomEventParameter* Parameters)
{
        // After sending the logs, check the delivered contents
}
// ADD 2.6.0 Start
void UMyStoveSDKObject::OnOverImmersion(FStoveOverImmersion OverImmersion)
{
        // Callback that is called every hour to prevent over-immersion
}

void UMyStoveSDKObject::OnShutdown(FStoveShutdown Shutdown)
{
        // Implement if selective shutdown is required by law.
}
// 2.6.0 End
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

You are not required to implement the OnStashCustomEvent, OnOverImmersion, OnShutdown callbacks. You only need to connect if your game uses the custom event log feature.

warning

The OnOverImmersion callback must be implemented in cases where game overimmersion/addiction precautions are required by law. The OnShutdown callback must be implemented if a selective shutdown is required by law.

# 2) Logging custom events

Log custom events (game logs) with UMyStoveSDKObject::StoveSDKStashCustomEvent function.

// input parameters
// const FString& Name: event name
// const FString& Category1: primary category name
// const FString& Category2 : 2nd category name
// const FString& SimpleValue : simple value
// const TArray<FStoveCustomEventParameter> Params: Detailed parameter information
// int paramsSize: Number of detailed parameter information
FStoveResult ErrorResult = UMyStoveSDKObject::StoveSDKStashCustomEvent("EVENT_NAME", "CATEGORY1", "CATEGORY2", 1.0f, params, PARAMS_SIZE);
if(ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
{
     /* handle success */
}
1
2
3
4
5
6
7
8
9
10
11
12

When the StoveSDKStashCustomEvent function is successfully processed, the OnStashCustomEvent callback is called.
The FStoveCustomEvent structure passed to the callback contains the event name passed when calling the API, the primary category name, the secondary category name, and a simple value.
The FStoveCustomEventParameter structure passed to the callback contains the parameter information passed when calling the API.

void UMyStoveSDKObject::OnStashCustomEvent(FStoveCustomEvent CustomEvent, int ParameterSize, FStoveCustomEventParameter* Parameters)
{
     /*Add the 'walkthrough' codes here.*/

     OnLog("[StashCustomEvent]");

     OnLog(" - CustomEvent.Name : %s", *(CustomEvent.Name));
     OnLog(" - CustomEvent.Category1 : %s", *(CustomEvent.Category1));
     OnLog(" - CustomEvent.Category2 : %s", *(CustomEvent.Category2));
     OnLog(" - CustomEvent.SimpleValue : %f", CustomEvent.SimpleValue);

     for (int i = 0; i < ParameterSize; i++, Parameters++)
     {
         OnLog(" - Parameter[%d].Name : %s", i, *(Parameters->Name));
         OnLog(" - Parameter[%d].Value : %s", i, *(Parameters->Value));
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Precautions

Callback Parameter The valid scope of FStoveCustomEvent/FStoveCustomEventParameter structure is limited to the callback function scope.
PC SDK frees internally allocated memory as soon as callback function execution is completed.
Therefore, if you need to save the information of FStoveCustomEvent/FStoveCustomEventParameter structure outside the scope of the callback function, you must create a copy through deep copy, and
When the use of the copy is complete, the memory must be freed.

# 3) Get PC SDK semantic version

Use the UMyStoveSDKObject::GetSDKVersion function to retrieve the version information of the PC SDK currently being integrated.

FString Version = UMyStoveSDKObject::StoveSDKGetSDKVersion();
if (Version.IsEmpty() == false)
{
     /* handle success */
}
1
2
3
4
5

# 4) Prevention of excessive immersion in games 2.6.0

The OnOverImmersion callback is called every hour after starting the game.
The FStoveOverImmersion structure passed to the callback contains the message, the elapsed time of using the game, and the minimum exposure time (in seconds) of the message.
The message is translated based on the language set in the PC SDK.

  • FStoveOverImmersion.Message: Overimmersion message
  • FStoveOverImmersion.ElapsedTimeInHours : elapsed time
  • FStoveOverImmersion.MinExposureTimeInSeconds : Minimum exposure time of message (in seconds)
void UMyStoveSDKObject::OnOverImmersion(FStoveOverImmersion OverImmersion)
{
     OnLog("[OverImmersion]");
 
     OnLog("- Message : %s", *(OverImmersion.Message));
     OnLog("- ElapsedTimeInHours : %d", OverImmersion. ElapsedTimeInHours);
     OnLog("- MinExposureTimeInSeconds : %d", OverImmersion.MinExposureTimeInSeconds);
     // Guidance on preventing excessive immersion in games
}
1
2
3
4
5
6
7
8
9

Guide to over-immersion messages

과몰입 메시지 : 게임을 플레이한 지 1 시간이 지났습니다. 과도한 게임이용은 정상적인 일상생활에 지장을 줄 수 있습니다.

# 5) shutdown

After starting the game, the OnShutdown callback is called based on the timetable registered in the shutdown system only for those subject to selective shutdown.
The OnShutdown callback can be called up to 4 times, and the time it is called and the actions to be taken in the game are as follows.

  • Shutdown event after successful PCSDK initialization
    • Shutdown notification 10 minutes ago: Shows only notification that you will be logged out after 10 minutes
    • Notification of shutdown 5 minutes ago: Shows only notification that you will be logged out after 5 minutes
    • Shutdown notification 1 minute ago: Displays only notification that you will be logged out after 1 minute
    • Shutdown Notification: Displays a notification that you will be logged out and ends the game immediately upon user confirmation

The FStoveShutdown structure passed to the callback contains the remaining time until shutdown, the message, and the message exposure time (seconds).

  • FStoveShutdown.InadvanceTimeInMinutes: The remaining time (minutes) until the user shuts down. If 0, the game ends immediately.
  • FStoveShutdown.Message : Shutdown notification message
  • FStoveShutdown.ExposureTimeInSeconds: message exposure time (seconds)
void UMyStoveSDKObject::OnShutdown(const FStoveShutdown Shutdown)
{
     //print shutdown information
     OnLog("[Shutdown]");

     OnLog("- InAdvanceTimeInMinutes : %d", Shutdown. InAdvanceTimeInMinutes);
     OnLog("- Message : %s", *(Shutdown.Message));
     OnLog("- ExposureTimeInSeconds : %d", Shutdown. ExposureTimeInSeconds);
}
1
2
3
4
5
6
7
8
9

Precautions

The valid scope of the callback parameter FStoveShutdown structure is limited to the scope of the callback function.
PC SDK frees internally allocated memory as soon as callback function execution is completed.
Therefore, if you need to save the information of the FStoveShutdown structure outside the scope of the callback function, you must create a copy through deep copy.
When the use of the copy is complete, the memory must be freed.

Shutdown Message Information

10 minutes : 회원님은 게임 시간 선택제 적용 대상으로 10 분 후 게임 이용이 제한됩니다.
5 minutes : 회원님은 게임 시간 선택제 적용 대상으로 5 분 후 게임 이용이 제한됩니다.
1 minutes : 회원님은 게임 시간 선택제 적용 대상으로 1 분 후 게임 이용이 제한됩니다.
0 minutes : 회원님은 게임 시간 선택제 적용 대상으로 게임 이용이 제한되어 게임을 종료합니다.

# 6) Lookup Tracking Clues

The UMyStoveSDKObject::StoveSDKGetTraceHint function retrieves a set of clues for tracing the stove platform logs.

FStoveTraceHint TraceHint = UStoveSDKObject::StoveSDKGetTraceHint();
if (TraceHint.ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
{
     OnLog("[GetTraceHint]");

     OnLog(" - TraceHint.SessionId : %s", *(TraceHint.SessionId));
     OnLog(" - TraceHint.RefSessionId : %s", *(TraceHint.RefSessionId));
     OnLog(" - TraceHint.Uuid : %s", *(TraceHint.Uuid));
     OnLog(" - TraceHint.ServiceProtocol : %s", *(TraceHint.ServiceProtocol));
     OnLog(" - TraceHint.RefResourceType : %s", *(TraceHint.RefResourceType));
}
else
{
     /* handle failure */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

The UStoveSDKObject::StoveSDKGetTraceHint function returns a FStoveTraceHint structure.
The returned FStoveTraceHint structure includes the session ID and reference session ID.
Also included are error codes for function calls.

# Updating Unreal Plugins

Guide for updating an existing Unreal Plugin to the new version. The StoveSDKPluing.uplugin file specifies the current version of the PCSDK.

{
    "FileVersion": 3,
    "Version": 1,
    "VersionName": "v2.5.0",
    "FriendlyName": "StoveSDKPlugin",
    "Description": "StoveSDK API for integrating Stove Client",
    "Category": "StoveSDK",
    "CreatedBy": "© Smilegate. All Rights Reserved.",
    "CreatedByURL": "https://www.onstove.com/",
    "DocsURL": "https://studio-docs.onstove.com/pc/GettingStarted/",
    "MarketplaceURL": "",
    "SupportURL": "",
    "CanContainContent": true,
    "IsBetaVersion": false,
    "Installed": true,
    "Modules": [
        {
            "Name": "StoveSDKPlugin",
            "Type": "Runtime",
            "LoadingPhase": "Default",
            "WhitelistPlatforms": [
                "Win64"
            ]
        }
    ],
    "Plugins": [

    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

Check the current version and download the latest version to update. After downloading and unzipping, a Plugins folder will be created.

Figure1

Copy the latest version of the Pluings folder and overwrite the Plugins folder in the game engine.

The Plugins folder linked to the game may also contain third-party plug-ins, so only StoveSDKPlugin is overwritten.

Once overwriting is complete, rebuild according to the Unreal Engine version from the right-click menu of the .uproject currently being used in the game project.

Figure1

When upgrading to Unreal v2.6.0 or higher

  • From v2.6.0, the spelling of function arguments, structure fields, etc. has changed according to the Unreal coding convention, so please check the coding convention in the latest guide.
  • If the version is PCSDK v2.0 or higher, it can be updated using the guide above.
Last Updated: 7/16/2024, 4:07:47 PM