# PC SDK Unreal 연동 가이드

# 소개

STOVE 플랫폼은 게임 배포 및 판매, 커뮤니티, 지표분석 등을 포함한, 게임 출시의 모든 과정을 원스탑으로 처리할 수 있는 통합 서비스를 제공합니다.

STOVE PC SDK(Unreal버전, 이하 PC SDK)를 사용하면 Stove 플랫폼이 제공하는 서비스를 게임에 쉽게 통합할 수 있습니다.

여기서는 PC SDK를 연동하는 방법에 대해 설명합니다.

confirm PC SDK 연동이 처음이라면, PC SDK Unreal 따라하기를 먼저 읽어보기 바랍니다.

# 사전준비

  • UNREAL 엔진 4.22.3 이상에서만 작동하며, 이하 버전은 Native StovePCSDK 연동이 필요합니다.
  • 스토브 가입 계정과 출시 게임용 App key, App secret, Game Id를 STOVE Studio (opens new window)에서 발급받았는지 확인합니다.
  • 비주얼 스튜디오 2015 업데이트 3 이상의 컴파일러가 설치되어 있는지 확인합니다.
  • PC SDK 다운로드 페이지에서, 최신 버전의 Unreal 배포 파일(이하 Plugin으로 표기)을 다운로드 합니다.

# Plugin 배포 파일 구성

Figure1

# 1) C API Include 폴더

Plugin을 다운로드하고 압축을 풀면 Plugins\StoveSDKPlugin\Binaries\ThirdParty\StoveSDKPluginLibrary\include 폴더에 아래 파일들이 포함되어 있습니다.

  • StovePCCallback.h
    • 스토브 플러그인과 NativeSDK API 호출 후 콜백을 전달받기 위한 콜백정의 헤더 파일입니다.
  • StovePCEnum.h
    • NativeSDK에서 에러, API타입, 비동기 상태 값등 Enum으로 정의 되어 있는 헤더 파일입니다.
  • StovePCDefine.h
    • 스토브 플러그인과 NativePCSDK 간의 커뮤니케이션을 위해 사용되는 API 호출결과(StovePCResult), 에러결과 구조체(FStoveError), 콜백 함수, API 요청/응답 파라미터 등이 선언되어 있습니다.
  • StovePCSDK.h
    • 스토브 플러그인과 NativePCSDK 간의 커뮤니케이션을 위해 사용되는 API 함수가 선언되어 있습니다.

# 2) Unreal API Include 폴더

Plugin 을 다운로드하고 압축을 풀면 Plugins\StoveSDKPlugin\Source\StoveSDKPlugin\Public 폴더에 아래 파일들이 포함되어 있습니다.

  • StoveSDKEnum.h
    • 스토브 플러그인에서 정의된 Enum 등이 선언 되어 있습니다.
  • StoveSDKNativeCallback.h
    • 스토브 플러그인과 NativePCSDK 간의 이벤트를 전달할 Callback 함수가 구현된 파일 입니다.
  • StoveSDKObject.h
    • UObject를 상속받은 NativePCSDK API를 래퍼한 UE4의 API 와 콜백을 전달 받을 UObject 타입의 클래스 입니다.
  • StoveSDKPlugin.h
    • 스토브 플러그인에서 NativePCSDK 모듈을 로드하기 위한 모듈래퍼 클래스입니다.
  • StoveSDKStruct.h
    • 스토브 플러그인에서 API 호출 후 전달할 구조체 집합 헤더입니다.
  • StoveSDKVersion.h
    • 스토브에서 언리얼 버전 체크를 위해 사용되는 파일입니다.
  • StoveSDKWebInterface.h
    • 스토브에서 제공하는 StoveWebPlugin 과 연동하기 위한 인터페이스 클래스입니다.

# 3) Bin 폴더

Plugins\StoveSDKPlugin\Binaries\ThirdParty\StoveSDKPluginLibrary\bin 폴더 하위에는 플랫폼(x64) 및 구성(Release)별로 필요한 바이너리가 포함되어 있습니다.

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

StovePCSDK.lib을 제외한 위 목록의 파일들은 게임 클라이언트를 최종 사용자에게 배포할 때 반드시 같이 배포되어야 합니다.

# 4) StoveSDKPlugin.uplugin

언리얼에서 플러그인을 인식하기 위한 파일입니다. 게임 프로젝트 내의 Plugins 안에 배치 되어야 합니다.

# 연동하기

  • StovePCSDK_Unreal은 언리얼 엔진의 UObject 타입의 클래스인 UStoveSDKObject클래스를 사용합니다. 여기에는 StovePCSDK 라이브러리의 데이터 타입과 인터페이스 및 콜백함수가 재정의 되어 있습니다. 연동하기 전 Plugin의 정의된 UStoveSDKObject를 상속받아 게임 프로젝트 내에 UMyStoveSDKObject를 구성한 후 사용해야 합니다.

  • Prefix
    UMyStoveSDKObject의 Prefix는 Unreal Engine 내에서 UObject 타입을 상속받은 클래스에 접두사 U를 붙이는 규칙을 그대로 따랐습니다.

상속받은 UObject에서 Plugin에 Import된 인터페이스를 Super를 통해 호출합니다.

  • Super
    상속받은 부모의 함수를 호출하기 위해 언리얼에서 제공하는 키워드는 Super 입니다.
FStoveResult UStoveSDKObject::StoveSDKInit(const FStoveConfig Config)
{
    FStoveResult ErrorResult = Super::StoveSDKInit(Config);
    return ErrorResult;
}
1
2
3
4
5

Plugin 환경 구성은 PC SDK Unreal 따라하기프로젝트 환경 구성하기 1~3번 항목을 참고하세요

# 1) Config, Callback 설정

PC SDK를 초기화하기 위해서는, 먼저 FStoveConfig 구조체에 값을 채운 뒤, 상속받은 Actor의 UStoveSDKObject::StoveSDKInit 함수를 호출합니다.
아래 코드를 참고하여 FStoveConfig 구조체의 각 필드 값을 채웁니다.

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

::warning 주의사항 PCSDK 로그경로는 절대적경로로 설정해야 합니다. ex) C:\Program Files\{Your Game Folder}\Logs 마지막에 "\"는 추가하지 않습니다. PCSDK 에서 "StovePCSDK.log" 파일명을 자동으로 추가합니다.
만약 "" 빈문자열로 경로를 설정하게 되면 PCSDK는 자동적으로 게임실행파일 폴더 또는 PCSDK DLL 이 위치한 폴더의 경로로 로그가 생성됩니다.

로그레벨 설정시 SANDBOX환경은 StovePCLogLevel::STOVE_PC_LOG_LEVEL_DEBUG 값으로 설정하고, LIVE환경은 StovePCLogLevel::STOVE_PC_LOG_LEVEL_ERROR 값으로 설정하기 바랍니다. :::

FStoveConfig 구조체 에 대한 설명은 Plugins\StoveSDKPlugin\Source\StoveSDKPlugin\Public폴더의 StoveSDKStruct.h 파일을 참고하세요.

게임 프로젝트에서 PC SDK의 API를 호출하고 그 결과를 확인하기 위해서는 콜백함수를 사용해야 합니다. 게임 프로젝트에서는 사용하게 되는 콜백함수는 아래와 같습니다.

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

필수적으로 연동해야 하는 OnError, OnInitCompleteOnOwnership 콜백함수 외의 나머지 콜백함수는 필요 시에만 연동을 하면 됩니다. 예를 들어, 소유권(Ownership) 기능만 사용하는 경우, 아래와 같이 게임 프로젝트에 정의해서 구현하면 됩니다.

/*소유권(Ownership) 기능만 사용하는 경우는,
필수 구현 콜백인 OnError, OnInitcomplte외에
OnOwnership 콜백만 추가로 구현해서 연결합니다.*/
void UMyStoveSDKObject::OnInitComplete()
{
    // 초기화 성공 후 처리내용
}
 
void UMyStoveSDKObject::OnError(FStoveError Error)
{
    // 에러에 대한 처리내용
}
 
void UMyStoveSDKObject::OnOwnership(int Size, FStoveOwnership* Ownerships)
{
    // 소유권 조회 후 처리내용
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 2) SDK 초기화

PC SDK의 API를 사용하기 전에 초기화를 위해 MyStoveSDKObject.cppUMyStoveSDKObject::StoveSDKInit 함수에 아래 코드와 같이 초기화 코드를 입력합니다.

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

UMyStoveSDKObject::StoveSDKInit함수는 config와 callback의 유효성 여부만 확인한 후, 즉시 FStovePCResult enum 타입 값을 반환합니다. 성공한 경우, STOVE_PC_NO_ERROR 값이 반환됩니다. 실패한 경우는 해당 에러 코드를 반환하며 게임 종료를 처리해야 합니다. 전체 에러 코드 목록은 StovePCDefine.h 파일의 StovePCResult enum을 확인하면 됩니다.

UMyStoveSDKObject::StoveSDKInit함수 내에서 config와 callback 유효성 확인이 진행되고, 그 외의 작업은 PC SDK에서 비동기로 처리됩니다. PC SDK의 비동기 작업이 성공적으로 완료된 경우, UMyStoveSDKObject::OnInitComplete 콜백이 호출되며, 에러가 발생한 경우는 UMyStoveSDKObject::OnError 콜백이 호출됩니다. 만약 초기화 시에 에러가 발생한 경우 UMyStoveSDKObject::OnError 함수에 전달된 StovePCError 구조체를 통해 에러 코드, 메시지 등을 확인할 수 있습니다. StovePCError 구조체 파라미터의 fError.result.result 값은 StovePCResult enum과 동일하여 에러코드로 에러상황을 유추 할 수 있습니다.

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()
{
    // 어쩌면 당신은 즉시 앱을 중단하기보다는 사용자에게 앱 중단에 대한 메시지를 보여준 후
    // 사용자 액션(e.g. 종료 버튼 클릭)에 따라 앱을 중단하고 싶어 할지도 모릅니다.
    // 그렇다면 여기에 당신만의 로직을 구현하십시오.
    // 권장하는 필수 사전 작업 오류에 대한 메시지는 아래와 같습니다.
    // 한국어 : 필수 사전 작업이 실패하여 게임을 종료합니다.
    // 그 외 언어 : 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

UMyStoveSDKObject::OnInitComplete 콜백이 오기 전, PC SDK의 초기화 상태 값을 조회할 필요가 있는 경우, UMyStoveSDKObject::GetInitState 함수를 사용할 수 있습니다.

/*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)
{
    /*초기화 완료
    OnInitComplete 콜백이 호출됨*/
    return FStoveResult{STOVE_PC_NO_ERROR};
}
else
{
    /*초기화 실패
    OnError 콜백이 호출됨*/
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 3) SDK 연동시 주의사항

confirm StoveSDKInit 함수의 파라미터인 FStovePCConfig 구조체의 로그레벨 설정시 Debug 빌드 시에는 StovePCLogLevel::STOVE_PC_LOG_LEVEL_DEBUG 값을 입력하고, 정식 빌드에는 StovePCLogLevel::STOVE_PC_LOG_LEVEL_ERROR 값으로 설정하여 불필요한 로그가 생성되는 것을 방지해 주시기 바랍니다.

confirm PC SDK 초기화가 완료되기 전에 GetToken, GetUser, GetOwnership 메서드를 호출하면 정상적으로 결과를 받지 못할 수 있습니다. 즉, PC SDK초기화 완료를 의미하는 OnInitComplete 콜백함수가 호출된 이후에 PC SDK의 GetToken, GetUser, GetOwnership 함수를 호출해야 정상적으로 결과값을 받을 수 있습니다.

# 4) SDK 종료

PC SDK 사용이 끝난 뒤에 StoveSDKUnInit함수를 호출하여 사용중인 리소스를 정리합니다. StoveSDKUnInit함수가 호출된 후에는 PC SDK의 API가 동작하지 않습니다.

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

# 5) 사용자 정보 얻기

UMyStoveSDKObject::StoveSDKGetUser 함수로 STOVE 런처에 로그인한 사용자 정보를 조회합니다.

FStoveResult UMyStoveSDKObject::StoveSDKGetUser()
{
    FStoveResult ErrorResult = Super::StoveSDKGetUser();
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*성공 처리*/
    }

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

UMyStoveSDKObject::StoveSDKGetUser 함수가 에러없이 실행되면 UMyStoveSDKObject::OnUser 콜백이 호출됩니다.
콜백에 전달되는 StovePCUser 구조체를 통해 사용자의 멤버넘버, 닉네임, 게임사용자아이디 정보들를 알 수 있습니다.

void UMyStoveSDKObject::OnUser(FStoveUser User)
{
    /*사용자 정보 출력*/
    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) 토큰 정보 얻기

UMyStoveSDKObject::StoveSDKGetToken 함수로 STOVE 런처에 로그인한 사용자의 토큰 정보를 얻어 옵니다.

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

UMyStoveSDKObject::StoveSDKGetToken 함수가 정상적으로 처리되면 UMyStoveSDKObject::OnToken 콜백이 호출됩니다.
콜백에 전달되는 StovePCToken 구조체에는 토큰 문자열이 포함되어 있습니다.

void UMyStoveSDKObject::OnToken(FStoveToken Token)
{
    /*토큰 정보 출력*/
    OnLog("AccessToken : %s", *(Token.AccessToken));
}
1
2
3
4
5

confirm 토큰이란? STOVE 런처에 로그인된 사용자의 엑세스토큰(Access Token)으로 게임서버가 이 엑세스토큰을 스토브 인증서버로 전달해서 로그인한 사용자의 유효성 검증을 수행할 수 있습니다. 엑세스토큰에 대한 상세한 설명은 store.support@smilegate.com로 기술지원을 받으시길 바랍니다

# 7) 소유권 정보 얻기

UMyStoveSDKObject::StoveSDKGetOwnership함수로 STOVE 런처의 사용자가 STOVE Studio에 등록된 게임을 구매해서 소유하고 있는지 여부를 조회할 수 있습니다.


FStoveResult UMyStoveSDKObject::StoveSDKGetOwnership()
{
    FStoveResult Result = Super::StoveSDKGetOwnership();
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        /*성공 처리*/
        /*소유권에 관한 정보는 OnOwnership 콜백으로 전달됩니다.*/ 
    }

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

UMyStoveSDKObject::StoveSDKGetOwnership함수가 정상적으로 처리되면 UMyStoveSDKObject::OnOwnership 콜백이 호출됩니다.
StovePCOwnership 구조체에 대한 세부 정보는 StovePCDefine.h 파일을 참고하세요.

아래는 OnOwnership 콜백에서 게임 구매 여부를 판단하는 예시 코드입니다. DLC가 없는 게임인 경우, 20~23 line의 확인 코드는 불필요합니다.

void UMyStoveSDKObject::OnOwnership(int size, FStoveOwnership* Ownership)
{
    bool owned = false;
 
    FStoveOwnership* data = Ownership;
    for (int i = 0; i < size; i++, data++)
    {
        if ((data->MemberNo != LOGIN_USER_MEMBER_NO /*StovePCUser 구조체의 memberNo*/)
            || (data->OwnershipCode != 1 /*1:소유권 획득, 2:소유권 해제(구매 취소한 경우)*/))
        {
            continue;
        }
 
        if (0 == wcscmp(L"YOUR_GAME_ID", *(data->GameId)) && data->GameCode == 3 /* // [GameCode] 3: BASIC 게임, 4: DEMO*/)
        {
           owned = true; // 소유권 확인 변수 true로 설정
        }
 
        /*DLC를 판매하는 게임일 때만 필요*/
        if (0 == wcscmp(L"YOUR_DLC_ID", *(data->GameId)) && data->GameCode == 5 /* 5: DLC*/)
        {
            /*YOUR_DLC_ID(DLC ID) 소유권이 있기에 DLC 플레이 허용*/
        }
    }
 
    if(owned)
    {
        // 소유권 검증이 정상적으로 완료된 이후 게임진입 로직 작성
    }
    else
    {
        // 소유권 검증실패 후 게임을 종료하고 에러메세지 표출 로직 작성
    }
     
     
}
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
  • 게임을 구매한 계정(소유권 보유)으로 STOVE 런처에 로그인한 후 게임을 플레이를 할 수 있습니다.
  • 게임 소유권이 없는 계정으로 STOVE 런처에 로그인한 후 exe 실행 시 아래 안내 메시지(예시)를 출력한 후 게임을 종료합니다.
    • 한국어 외의 OS : "Please log in to STOVE Client with the account that has purchased the game."
    • 한국어 : "게임을 구매한 계정으로 STOVE 클라이언트에 로그인하시기 바랍니다."

confirm 게임 소유권이 있는 계정이 없어도 소유권 기능을 테스트할 수 있으며, 자세한 방법은 FAQ를 확인하시기 바랍니다.

# 8) 언어 설정 2.6.0

UMyStoveSDKObject::StoveSDKSetLanguage 함수로 언어를 설정합니다.
PC SDK는 초기화시 시스템 언어(운영체제 언어)를 이용하여 언어를 기본으로 설정합니다.
명시적으로 시스템 언어(운영체제 언어)를 설정하려면 파라미터로 system을 입력합니다.
특정 언어를 설정하기 위해서는 초기화 성공 이후(e.g. OnInitComplete) UMyStoveSDKObject::StoveSDKSetLanguage 함수를 호출합니다.

FStoveResult UMyStoveSDKObject::StoveSDKSetLanguage(const FString& Language)
{
    FStoveResult ErrorResult = Super::StoveSDKSetLanguage(Language);
    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
       // 성공처리 
    }
    return ErrorResult;
}
1
2
3
4
5
6
7
8
9

# 9) 언어 번역 2.6.0

UMyStoveSDKObject::StoveSDKTranslateLanguage 함수로 언어를 번역합니다.
PC SDK는 설정된 언어 정보를 기반으로 특정 문자열에 대한 번역본을 제공합니다.
특정 문자열은 PC SDK 에서 관리하는 문자열 아이디(String Id)로 관리됩니다.
게임에서 PC SDK 팝업 UI 를 직접 구현하는 경우 UI에 표시되는 문자열은 UMyStoveSDKObject::StoveSDKTranslateLanguage 함수를 통해 번역된 문자열을 표시해야 합니다.

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

주의사항

PC SDK에 설정된 언어에 대해 특정 문자열의 번역본이 없는 경우 영어 번역본을 리턴하며,
예외 발생 또는 지원하지 않는 문자열 아이디에 대해서는 입력 파라미터(문자열 아이디)를 그대로 리턴합니다.-

# 에러 확인

PC SDK 사용 중 발생하는 에러는 크게 두 가지 경우로 구분해서 확인할 수 있습니다.

# 함수 호출 후 반환되는 StovePCResult enum 값

PC SDK의 모든 함수는 호출 직후, 호출이 성공했는지 여부를 나타내는 StovePCResult enum 값을 반환합니다.
전체값은 PC SDK 오류 코드 페이지에서 확인 할 수 있습니다.

# OnError 콜백을 통해 전달되는 StovePCError 구조체

PC SDK 함수 중, 비동기로 동작하는 함수에서 에러가 발생한 경우는 UMyStoveSDKObject::OnError 콜백이 호출되며, 에러에 대한 설명이 포함된 StovePCError 구조체가 전달됩니다.

/*OnError 콜백이 호출될 때 전달 됩니다.*/
struct StovePCError
{
    /*호출된 함수를 나타내는 enum 값*/
    StovePCFunctionType functionType;

    /*발생한 에러 유형을 나타내는 enum 값*/
    StovePCResult result;

    /*발생한 에러 메시지*/
    char* message;

    /*외부 에러(http 에러, 외부 모듈 에러)가 발생한 경우, 해당하는 에러 코드*/
    int externalError; 
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 팝업 연동하기

PC SDK는 팝업을 게임에 통합할 수 있도록 API를 제공합니다. PC SDK가 지원하는 팝업으로는 자동, 수동, 뉴스, 쿠폰, 커뮤니티가 있습니다.
PC SDK는 팝업을 위한 데이터를 게임에 제공합니다. 게임은 제공받은 데이터를 이용해 팝업뷰를 생성합니다.
각각의 팝업은 아래와 같이 정의합니다.

  • 자동 팝업 : 게임 로비화면에 가장 많이 노출하며 광고와 이벤트 등을 보여주는 팝업
  • 수동 팝업 : 리소스키에 해당하는 등록된 이벤트를 보여주는 팝업
  • 뉴스 팝업 : 공지성 게시글을 한 번에 모아서 보여주는 팝업
  • 쿠폰 팝업 : 쿠폰 등록 페이지를 보여주는 팝업
  • 커뮤니티 팝업 : 게임 커뮤니티 페이지를 보여주는 팝업

PC SDK 팝업 API를 사용하기 위해서는 파트너스를 통합 팝업의 메타데이터 등록이 선행되어야 합니다.

# 1) Callback 설정

팝업 API를 사용하여 PC SDK와 커뮤니케이션 하기 위하여, 게임에서는 아래 UStoveSDKObject 클래스의 정의된 콜백함수를 재정의해야 합니다.

//StovePCSDK Callback
UCLASS()
class HELLOSTOVE_API UMyStoveSDKObject : public UStoveSDKObject
{
    GENERATED_BODY()
 
//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;
  
 
    /// GetAutoPopup 처리가 완료됐을 때 호출되는 콜백
    void OnAutoPopup(int Size, FStoveAutoPopup* AutoPopups, int HeaderSize, FStovePopupRequestHeader* Headers) final;
     
     /// GetManualPopup 처리가 완료됐을 때 호출되는 콜백
    void OnManualPopup(int Size, FStoveManualPopup* ManualPopups, int HeaderSize, FStovePopupRequestHeader* Headers) final;
    
    /// GetNewsPopup 처리가 완료됐을 때 호출되는 콜백
    void OnNewsPopup(FStoveNewsPopup NewsPopups, int HeaderSize, FStovePopupRequestHeader* Headers) final;          
     
    /// GetCouponPopup 처리가 완료됐을 때 호출되는 콜백
    void OnCouponPopup(FStoveCouponPopup CouponPopup, int HeaderSize, FStovePopupRequestHeader* Headers) final;                        
 
    /// GetCommunityPopup 처리가 완료됐을 때 호출되는 콜백
    void OnCommunityPopup(FStoveCommunityPopup CommunityPopup, int CookieSize, FStovePopupRequestCookie* Cookies) 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

OnAutoPopup, OnManualPopup, OnNewsPopup, OnCouponPopup, OnCommunityPopup 콜백을 반드시 구현할 필요는 없습니다.
게임에서 사용하는 팝업에 맞게 필요한 콜백 함수만 구현하여 연결하면 됩니다.

# 2) 게임 프로필 설정

UMyStoveSDKObject::StoveSDKSetGameProfile 함수로 게임의 월드와 캐릭터 정보를 설정합니다.
설정된 정보는 팝업에서 활용되므로 팝업을 사용하기 전에 반드시 설정되어야 합니다.
게임프로필의 유효성은 별도로 검사하고 있지 않습니다. 때문에 입력시 유효성 체크(null)를 진행하여 값을 정확히 입력해야 합니다.
입력한 게임프로필은 PCSDK 수명주기 동안만 유효합니다.
즉, PCSDK 를 초기화 할 때 마다 UMyStoveSDKObject::StoveSDKSetGameProfile 함수를 호출하여 게임의 월드와 캐릭터 정보를 설정해야 합니다.

// 입력 파라미터
// const FString& WorldId: 게임의 월드 식별자
// const FString& CharacterNo: 캐릭터 식별자
 

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)
    {
          //성공처리
    }

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

# 3) 자동팝업 정보 얻기

UMyStoveSDKObject::StoveSDKGetAutoPopup 함수로 자동팝업에 대한 정보를 조회합니다.

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

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

UMyStoveSDKObject::StoveSDKGetAutoPopup 함수가 정상적으로 처리되면 UMyStoveSDKObject::OnAutoPopup 콜백이 호출됩니다.
콜백에 전달되는 FStoveAutoPopup 구조체에는 자동팝업에 대한 URL이 포함되어 있습니다.
콜백에 전달되는 FStovePopupRequestHeader 구조체에는 URL 요청시 셋팅할 헤더의 이름/값 쌍이 포함되어 있습니다.

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("- AutoPopup[%d].Control.UI.CloseButtonImage.Normal.FileId :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Normal.FileId));
        OnLog("- AutoPopup[%d].Control.UI.CloseButtonImage.Normal.FileUrl :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Normal.FileUrl));
        OnLog("- AutoPopup[%d].Control.UI.CloseButtonImage.Pressed.FileId :%s", i, *(AutoPopups->Control.UI.CloseButtonImage.Pressed.FileId));
        OnLog("- AutoPopup[%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

주의사항

성공 콜백(OnAutoPopup)이 실행 되었다고 해도 Size 콜백파라미터가 0 인 경우가 있습니다. 이때 AutoPopups 콜백파라미터는 빈 배열이 전달 됩니다.
AutoPopups 콜백파라미터를 사용하기 전에 Size 콜백파라미터를 먼저 확인 후 팝업을 띄울지 말지를 결정해야 합니다. 이런 경우 파트너스의 자동팝업 설정을 확인합니다.

자동팝업의 노출 순서는 AutoPopups 배열요소의 순서와 동일해야 합니다. 예를 들면 AutoPopups 배열이 [A,B,C] 세개의 요소를 포함한다면 A, B, C 순서로 팝업을 노출해야 합니다

UMyStoveSDKObject::StoveSDKGetAutoPopup 함수가 실행중에 오류가 발생하면 UMyStoveSDKObject::OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
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) 수동팝업 정보 얻기

UMyStoveSDKObject::StoveSDKGetManualPopup 함수로 수동팝업에 대한 정보를 조회합니다.

// 입력 파라미터
// const FString& ResourceKey: 파트너스에서 등록한 수동팝업 식별자
  
FStoveResult UMyStoveSDKObject::StoveSDKGetManualPopup(const FString& ResourceKey)
{
    /*Add the 'walkthrough' codes here.*/
    FStoveResult ErrorResult = Super::StoveSDKGetManualPopup(ResourceKey);

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

UMyStoveSDKObject::StoveSDKGetManualPopup 함수가 정상적으로 처리되면 UMyStoveSDKObject::OnManualPopup 콜백이 호출됩니다.
콜백에 전달되는 FStoveManualPopup 구조체에는 수동팝업에 대한 URL이 포함되어 있습니다.
콜백에 전달되는 FStovePopupRequestHeader 구조체에는 URL 요청시 셋팅할 헤더의 이름/값 쌍이 포함되어 있습니다.

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

주의사항

성공 콜백(OnManualPopup)이 실행 되었다고 해도 Size 콜백파라미터가 0 인 경우가 있습니다.
이때 ManualPopups 콜백파라미터는 빈 배열이 전달 됩니다. ManualPopups 콜백파라미터를 사용하기 전에 Size 콜백파라미터를 먼저 확인 후 팝업을 띄울지 말지를 결정해야 합니다.
이런 경우 파트너스의 수동팝업 설정을 확인합니다.

수동팝업의 노출 순서는 ManualPopups 배열요소의 순서와 동일해야 합니다. 예를 들면 ManualPopups 배열이 [A,B,C] 세개의 요소를 포함한다면 A, B, C 순서로 팝업을 노출해야 합니다.

UMyStoveSDKObjcet::StoveSDKGetManualPopup 함수가 실행중에 오류가 발생하면 UMyStoveSDKObjcet::OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
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) 뉴스팝업 정보 얻기

UMyStoveSDKObject::StoveSDKGetNewsPopup 함수로 뉴스팝업에 대한 정보를 조회합니다.

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

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

UMyStoveSDKObject::StoveSDKGetNewsPopup 함수가 정상적으로 처리되면 UMyStoveSDKObject::OnNewsPopup 콜백이 호출됩니다.
콜백에 전달되는 FStoveNewsPopup 구조체에는 뉴스팝업에 대한 URL이 포함되어 있습니다.
콜백에 전달되는 FStovePopupRequestHeader 구조체에는 URL 요청시 셋팅할 헤더의 이름/값 쌍이 포함되어 있습니다.

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

주의사항

성공 콜백(OnNewsPopup)이 실행 되었다고 해도 NewsPopup 콜백파라미터의 속성들이 기본값(빈 문자열 또는 0)인 경우가 있습니다.
NewsPopup 콜백파라미터의 url 속성을 먼저 확인 후 팝업을 띄울지 말지를 결정해야 합니다.
이런 경우 파트너스의 뉴스팝업 설정을 확인합니다.

UMyStoveSDKObject::StoveSDKGetNewsPopup 함수가 실행중에 오류가 발생하면 UMyStoveSDKObject::OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
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) 쿠폰팝업 정보 얻기

UMyStoveSDKObject::StoveSDKGetCouponPopup 함수로 쿠폰팝업에 대한 정보를 조회합니다.

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

UMyStoveSDKObject::StoveSDKGetCouponPopup 함수가 정상적으로 처리되면 UMyStoveSDKObject::OnCouponPopup 콜백이 호출됩니다.
콜백에 전달되는 FStoveCouponPopup 구조체에는 쿠폰팝업에 대한 URL이 포함되어 있습니다.
콜백에 전달되는 FStovePopupRequestHeader 구조체에는 URL 요청시 셋팅할 헤더의 이름/값 쌍이 포함되어 있습니다.

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

UStoveSDKObject::StoveSDKGetCouponPopup 함수가 실행중에 오류가 발생하면 UStoveSDKObject::OnError 콜백이 호출됩니다.

# 7) 커뮤니티팝업 정보 얻기

UMyStoveSDKObject::StoveSDKGetCommunityPopup 함수로 커뮤니티팝업에 대한 정보를 조회합니다.

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

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

         //성공처리
    }

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

UMyStoveSDKObject::StoveSDKGetCommunityPopup 함수가 정상적으로 처리되면 UStoveSDKObject::OnCommunityPopup 콜백이 호출됩니다.
콜백에 전달되는 FStoveCommunityPopup 구조체에는 커뮤니티팝업에 대한 URL이 포함되어 있습니다.
콜백에 전달되는 FStovePopupRequestCookie 구조체에는 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

UMyStoveSDKObject::StoveSDKGetCommunityPopup 함수가 실행중에 오류가 발생하면 UStoveSDKObject::OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
13008 Mandatory Parameter missing
90001 AccessToken invalid
40101 Invalid token

# 8) 팝업 불허 설정 2.6.0

UMyStoveSDKObject::StoveSDKSetPopupDisallowed 함수로 일정기간 동안 특정 팝업이 표시되지 않도록 설정합니다.
게임에서 PC SDK 팝업 UI 를 직접 구현하는 경우 팝업 UI 정보의 Control.UI.Visible.DisallowedButton 값을 참고하여 UI 를 구성하고
버튼 클릭 핸들러에서 UMyStoveSDKObject::StoveSDKSetPopupDisallowed 함수를 호출합니다.
UMyStoveSDKObject::StoveSDKSetPopupDisallowed 함수를 호출시 days 파라미터는 팝업 정보의 Control.UI.DisallowedDay 값을 사용합니다.
팝업 불허가 설정되면 불허기간 동안 해당 팝업 정보는 조회되지 않습니다.

// 입력 파라미터
// const int PopupId : 파트너스에서 발급된 팝업 식별자
// const int Days : 파트너스에서 등록한 불허 기간(일단위)
//const int Days : 파트너스에서 등록한 불허 기간(일단위) 또는 -1(다시 보지 않기)

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)
    {
        // 성공처리
    }

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

# 빌링 연동하기 2.6.0

PC SDK는 스토브 플랫폼의 빌링서비스를 게임에 통합할 수 있도록 API를 제공합니다. 빌링서비스로는 상점이 있습니다.
상점에 대한 일반적인 시나리오는 아래와 같습니다. 이는 게임의 상황(e.g. 게임서버 유무)에 따라 조금씩 달라질 수 있습니다.

  • 상점 구성을 위한 정보는 상점 카테고리 조회 및 상품 조회 API를 통해 획득합니다.
  • 게임은 획득한 카테고리 및 상품 정보를 통해 상점을 구성하여 UI를 표시합니다.
  • 각 상품에 대한 구매는 구매 시작 API를 호출하여 1회용 결제 URL을 획득합니다.
    • 판매가격이 0 인 상품의 경우
      • 구매 시작 API 응답을 받는 시점에 구매가 완료되어 있습니다.
    • 판매가격이 0 보다 큰 상품의 경우
      • 구매 시작 API의 응답에서 1회용 결제 URL을 획득합니다.
      • 게임은 1회성 결제 URL을 외부브라우저로 탐색합니다. 지원브라우저 : Chrome(75이상), Edge(42이상)
      • 이후 결제 진행은 웹페이지를 통해 완료됩니다.
  • 결제가 완료되면 게임은 구매 상태 확인 API를 호출하여 구매 상태를 확인합니다.
  • 결제가 정상적으로 완료된 것으로 확인되면 게임은 상품을 지급합니다.
  • 구매 검증 API를 통해 상품 구매 이력(1회 이상 구매 여부)을 확인 할 수 있습니다.
  • 보관함 조회 API를 통해 아이템 복원등에 활용할 수 있습니다.

PC SDK 빌링서비스 API를 사용하기 위해서는 파트너스를 통한 빌링서비스의 메타데이터 등록이 선행되어야 합니다.
또한 PC SDK를 통해 상점을 이용하는 경우 UMyStoveSDKObject::StoveSDKIAPInit 함수를 호출하여 파트너스로부터 발급 받는 ShopKey를 전달해야 합니다.
ShopKey 설정 없이 빌링서비스 API를 호출할 경우 에러가 반환됩니다.

게임은 상점 열기를 할 때마다 서비스 이용 약관 동의 여부를 체크하여야 합니다.
게임 이용자의 서비스 이용 약관 동의 여부가 미동의인 경우 PCSDK 가 제공하는 약관동의 페이지 Url을 이용하여 브라우저를 열어 게임 이용자가 서비스 이용 약관 동의를 할 수 있도록 합니다.
게임 이용자가 서비스 이용 약관을 동의 이후 상점 열기를 하면 상점으로 진입합니다.

PC SDK는 상점 지원을 위해 내부에 캐시를 운영합니다.

UMyStoveSDKObject::StoveSDKFetchProducts 함수의 isRefresh 파라미터를 통해 상품 정보를 캐시에서 가져올지 Web API를 통해 가져올지 결정할 수 있습니다.
Web API를 통해 가져온 상품 정보는 캐시에 전체 또는 부분(카테고리별)적으로 업데이트 된 후 게임에 상품 정보를 콜백으로 전달합니다.
(다만, 캐시가 비어 있으면 isRefresh 파라미터 값과 관계없이 Web API를 통해 상품 정보를 조회하여 캐시에 업데이트 합니다.)
또한 PC SDK는 UMyStoveObject::StoveSDKConfirmPurchase 함수 호출 시점에 Web API 응답을 통해 각 상품의 구매/판매수량 및 구매여부를 캐시에 업데이트 합니다.

# (예시)빌링 연동 흐름도

confirm confirm

  1. 게임 시작 시 PC_SDK 초기화
  • UMyStoveSDKObject::StoveSDKIAPInit 함수를 통하여 IAP를 초기화 합니다.
  • IAP 초기화 시 전체 아이템 리스트를 조회 후 내장 캐시에 저장합니다.
  1. 인게임 내 상점 페이지 진입 시 미지급 조회 처리(선택사항)
  • UMyStoveSDKObject::StoveSDKFetchInventory 보관함 조회를 통하여 결재 완료 후 미지급된 아이템이 있는 경우 재지급 처리 합니다.
  1. 상점 진입 후 상점구성을 위해 카테고리 리스트를 조회 합니다.
  • UMyStoveSDKObject::StoveSDKFetchShopCategories 함수를 통하여 상점내 카테고리를 조회 합니다.
  1. 3번에서 조회 된 상점 내 카테고리 정보를 통해 아이템 정보를 조회 합니다.
  • UMyStoveSDKObject::StoveSDKFetchProducts 함수를 통하여 카테고리에 포함된 상품 정보를 조회 합니다.
  1. 상점에서 구매상품을 선택합니다.
  • 구매 상품 정보는 배열로 직접 구성 하여야 합니다.(PruductId/SalePrice/Quantity)
  • Quantity는 반드시 1로 지정 필요 합니다.
  1. 상품구매 시작을 위해 1회용 결제 URL 정보를 조회 합니다.
  • UMyStoveSDKObject::StoveSDKStartPurchase 함수를 통해서 1회용 결재창 URL 정보를 조회 합니다.
  1. 인게임 내에서 상품결제안내 팝업을 처리합니다.(외부 브라우져 결재 결과 체크를 위해 반드시 처리해야 합니다.)
  2. 6번을 통해 얻은 1회용 결제 URL 정보로 외부 브라우져를 팝업합니다.
  3. Stove 빌링의 결제창을 통해 제품 결제를 진행합니다.
  • 결제창에서 결재가 완료 된 후 브라우저를 종료 합니다.
  1. 인 게임내 7번에서 생성한 상품결제안내 팝업에서 "결재완료" 버튼을 클릭 시 구매상태 정보를 조회 합니다.
  • UMyStoveSDKObject::StoveSDKConfirmPurchase 함수를 통해서 결재 상태에 대한 정보를 조회 합니다.
  • 결재완료 상태 확인 후 팝업 종료 후 상점페이지로 돌아갑니다.
  1. 구매동선이 완료 됩니다.

참고

외부 브라우저를 통해 Stove 결재 미진행 및 UMyStoveSDKObject::StoveSDKStartPurchase를 통해서 결재 결과를 알수 없는 경우
상점 페이지 진입(2번) 시 UMyStoveSDKObject::StoveSDKFetchInventory 보관함 조회를 통하여 아이템을 재지급 처리 합니다.


아래 시퀀스 다이어그램은 가상의 상점 운용 시나리오를 보여줍니다.
이는 일반적인 케이스에 대한 일례로써 게임의 상황(e.g. 상점 카테고리 구조, 상점 UI 생성 시점 etc)에 따라 다소 차이가 있을 수 있습니다.

  • PCSDK IAP 초기화
  • 서비스 이용 약관 동의 여부 체크
  • 상점 열기
  • 상품 구매
  • 상품 구매 상태 확인
  • 상품 구매 이력 검증
  • 아이템 복원 처리

# 1) Callback 설정

빌링서비스 API를 사용하여 PC SDK와 커뮤니케이션 하기 위하여, 게임에서는 아래 UMyStoveSDKObject 클래스의 정의된 콜백함수를 재정의해야 합니다.

//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;

    // FetchShopCategories 처리가 완료됐을 때 호출되는 콜백
    void OnFetchShopCategories(int Size, FStoveShopCategories* Categories) final;

    // FetchProducts 처리가 완료됐을 때 호출되는 콜백    
    void OnFetchProducts(int Size, FStoveProduct* Products) final;

    // StartPurchase 처리가 완료됐을 때 호출되는 콜백
    void OnStartPurchase(FStovePurchase Purchase) final;

    // ConfirmPurchase 처리가 완료됐을 때 호출되는 콜백
    void OnConfirmPurchase(int Size, FStovePurchaseProduct* PurchaseProducts, bool Status, FString ShopKey) final;

    // FetchInventory 처리가 완료됐을 때 호출되는 콜백    
    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

연동하기 2) Config, Callback 설정에서와 같이 콜백함수를 재정의 하여 이벤트를 전달 받습니다.

// 빌링서비스
void UMyStoveSDKObject::OnFetchTermsAgreement(const FStoveTermsAgreement TermsAgreement)
{
   // 서비스 이용 약관
}
void UMyStoveSDKObject::OnFetchShopCategories(int Size, FStoveShopCategories* Categories)
{
   // 상점 카테고리 API 호출후 
}

void UMyStoveSDKObject::OnFetchProducts(int Size, FStoveProduct* Products)
{
   // 상점에 등록된 상품 API 호출 후 
}
void UMyStoveSDKObject::OnStartPurchase(FStovePurchase Purchase)
{
   // 상품 결제 시도 후 
}
void UMyStoveSDKObject::OnConfirmPurchase(int Size, FStovePurchaseProduct* PurchaseProducts, bool Status, FString ShopKey)
{
   // 상품 구매 확인 후 
}
void UMyStoveSDKObject::OnFetchInventory(int Size, FStoveInventoryItem* InventoryItems)
{
   // 보관함 조회 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

OnFetchTermsAgreement, OnFetchShopCategories, OnFetchProducts, OnStartPurchase, OnConfirmPurchase, OnFetchInventory 콜백을 반드시 구현할 필요는 없습니다.
게임에서 상점이 필요한 경우만 연결하면 됩니다. 단, 상점 기능을 위해서는 5개의 콜백을 모두 구현하여 연결하여야 합니다.

# 2) IAP 초기화

게임에서 PCSDK 를 사용해서 빌링서비스를 제공하기로 결정하였다면, 스토브에서 발급된 상점키 ShopKey 인자값으로 UMyStoveSDKObject::StoveSDKIAPInit 함수로 빌링 초기화를 시도합니다.

빌링초기화 시도시 스토브 플랫폼에 등록된 상품리스트를 자동으로 조회한 후 스토브 PCSDK 내부 캐시에 저장을 합니다.
UMyStoveSDKObject::StoveSDKIAPInit 함수를 호출하고 실패하였다면 FStoveResultOnError 콜백으로 에러내용을 전달합니다.

// 입력 파라미터
// FString ShopKey : 스토브에서 발급받은 ShopKey

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

    FStoveResult ErrorResult = Super::StoveSDKIAPInit(ShopKey);

    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
       //성공처리
    }

    return ErrorResult;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ExternalError 설명
500 Internal Server Error
50001 상점이 존재하지 않거나, 점검 중
50002 상품이 존재 하지 않거나 판매 불가능 상품
999999 정의되지 않은 오류

# 3) 게임프로필 설정

UMyStoveSDKObject::StoveSDKSetGameProfile 함수로 게임의 월드와 캐릭터 정보를 설정합니다.
이는 상품 구매 주체의 수준을 결정하기 위함입니다. PC SDK는 상품 구매 주체의 우선순위를 아래와 같이 매깁니다.

  • Character No. > Guid > Member No.

UMyStoveSDKObject::StoveSDKSetGameProfile 함수를 통해 캐릭터 정보가 설정되면 PC SDK는 상품 구매시 Character No.를 기준으로 구매를 진행합니다.
반면에 UMyStoveSDKObject::StoveSDKSetGameProfile 함수를 통해 캐릭터 정보가 설정되지 않은 경우, PC SDK는 Guid 또는 Member No.를 기준으로 구매를 진행합니다.
따라서 상품 구매시 상품 구매 주체가 잘 적용되도록 하려면 PC SDK의 빌링서비스 API를 호출하기 전에 UMyStoveSDKObject::StoveSDKSetGameProfile API 호출 여부를 고려해야 합니다.
일반적으로 UMyStoveSDKObject::StoveSDKSetGameProfile 함수는 월드/캐릭터 변경시마다 1회만 호출하면 됩니다.

# 4) 서비스 이용 약관 동의 여부 조회

UMyStoveSDKObejct::StoveFetchTermsAgreement 함수로 해당 게임에 대한 사용자의 서비스 이용 약관 동의 정보를 조회합니다.

FStovePCResult ErrorResult = StoveSDKFetchTermsAgreement();
if(ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
{
    // 성공 처리
}
1
2
3
4
5

UMyStoveSDKObejct::StoveFetchTermsAgreement 함수가 정상적으로 처리되면 OnFetchTermsAgreement 콜백이 호출됩니다.
콜백에 전달되는 StovePCTermsAgreement 구조체에는 약관 동의에 대한 메타정보가 포함되어 있습니다.

FStoveTermsAgreement.GameId: 게임 아이디
FStoveTermsAgreement.Result : 서비스 이용 약관 동의 여부
FStoveTermsAgreement.Region: 권역 코드
FStoveTermsAgreement.AgreementUrl : 서비스 약관 동의 동의 페이지 Url
void UMyStoveSDKObject::OnFetchTermsAgreement(const FStoveTermsAgreement TermsAgreement)
{
    /*Add the 'walkthrough' codes here.*/
    OnLog("[OnFetchTermsAgreement]");

    OnLog(" GameId : %s", *(TermsAgreement.GameId));
    OnLog(" Result : %s",  TermsAgreement.Result ? TEXT("true") : TEXT("false"));
    OnLog(" Region : %s", *(TermsAgreement.Region));
    OnLog(" AgreementUrl : %s", *(TermsAgreement.AgreementUrl));

    if (TermsAgreement.Result == false)
    {
        FWindowsPlatformProcess::LaunchURL(*(TermsAgreement.AgreementUrl), nullptr, nullptr);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

UMyStoveSDKObejct::StoveFetchTermsAgreement 함수가 실행중에 오류가 발생하면 OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
400 잘못된 요청 정보
500 시스템 에러
70898 유효하지 않은 데이터
70899 파라미터에 유효하지 않은 값이 존재
70800 해당 조건으로 존재하는 약관 없음
70804 GS API 호출에러
70805 GUID API 호출 에러
70806 서비스를 찾을 수 없음
70807 GUID API 에서 정의되지 않은 오류 발생
40103 토큰 만료

# 4) 상점 카테고리 정보 얻기

UMyStoveSDKObject::StoveSDKFetchShopCategories 함수로 해당 게임에 대한 상점 카테고리 정보를 조회합니다.
카테고리 정보에는 부모 카테고리에 대한 아이디를 포함하고 있어 계층적 구조로 상점을 구성할 수 있습니다.

FStoveResult UMyStoveSDKObject::StoveSDKFetchShopCategories()
{
    FStoveResult ErrorResult = Super::StoveSDKFetchShopCategories();
    if(ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
        // 성공 처리
    }

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

UMyStoveSDKObject::StoveSDKFetchShopCategories 함수가 정상적으로 처리되면 OnFetchShopCategories 콜백이 호출됩니다.
콜백에 전달되는 FStoveShopCategory 구조체에는 상점 카테고리에 대한 메타정보가 포함되어 있습니다.

  • FStoveShopCategory.CategoryId : 카테고리 아이디
  • FStoveShopCategory.ParentCategoryId : 부모 카테고리 아이디
  • FStoveShopCategory.DisplayNo : 카테고리 순서
  • FStoveShopCategory.Name : 카테고리명
  • FStoveShopCategory.Depth : 카테고리 깊이 (최상위 카테고리의 경우 1)
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

UMyStoveSDKObejct::StoveSDKFetchShopProducts 함수가 실행중에 오류가 발생하면 OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
500 Internal Server Error
999999 정의되지 않은 오류

# 5) 상품 정보 얻기

UMyStoveSDKObject::StoveSDKFetchProducts 함수로 해당 게임에 대한 상품 정보를 조회합니다.

// 입력 파라미터
// FString CategoryId : 파트너스에서 등록한 카테고리 식별자(빈문자열 전달시 전체 카테고리 조회)
// bool IsRefresh : true 인 경우 Web API 조회, false 인 경우 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)
    {
        // 성공처리 
    }

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

UMyStoveSDKObject::StoveSDKFetchProducts 함수가 정상적으로 처리되면 OnFetchProducts 콜백이 호출됩니다.
콜백에 전달되는 FStoveProduct 구조체에는 상품에 대한 메타정보가 포함되어 있습니다.

  • FStoveProduct.ProductId : 상품 아이디
  • FStoveProduct.GameItemId : 상품 아이디에 매핑되는 게임 내 아이템 아이디
  • FStoveProduct.Name : 상품명
  • FStoveProduct.Description : 상품 설명
  • FStoveProduct.Quantity : 개별 상품 수량
  • FStoveProduct.ProductTypeCode : 상품 유형 코드 (1: 패키지 게임 상품, 2: 인 게임 상품, 3: 패키지 아이템)
  • FStoveProduct.CategoryId : 카테고리 아이디
  • FStoveProduct.CurrencyCode : 통화 코드
  • FStoveProduct.Price : 상품 정가 (표기시에는 CurrencyCode 가 "KRW" 와 같으면 소수점 이하 생략 표기, 다르면 소수점 둘째자리까지 표기)
  • FStoveProduct.SalePrice : 상품 판매가 (표기시에는 CurrencyCode 가 "KRW" 와 같으면 소수점 이하 생략 표기, 다르면 소수점 둘째자리까지 표기)
  • FStoveProduct.IsDiscount : 할인 여부
  • FStoveProduct.DiscountType : 할인 유형(1: 정률, 2: 정액)
  • FStoveProduct.DiscountTypeValue : 할인값
  • FStoveProduct.DiscountBeginDate : 할인 시작 일자(UTC+0)
  • FStoveProduct.DiscountEndDate : 할인 종료 일자(UTC+0)
  • FStoveProduct.TotalQuantity : 상품 총 판매 수량
  • FStoveProduct.MemberQuantity : 회원 구매 수량
  • FStoveProduct.GuidQuantity : Guid 구매 수량(상품 구매 주체[CharacterNo/Guid/MemberNo]의 구매 수량)
  • FStoveProduct.ThumbnailUrl : 대표 상품 이미지
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

UMyStoveSDKObject::StoveSDKFetchProducts 함수가 실행중에 오류가 발생하면 OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
500 Internal Server Error
50001 상점이 존재하지 않거나, 점검 중
50002 상품이 존재 하지 않거나 판매 불가능 상품
999999 정의되지 않은 오류

# 6) 상품 구매 시작

UMyStoveSDKObject::StoveSDKStartPurchase 함수로 상품 구매를 시작합니다.

// 입력 파라미터
// const TArray<FStoveOrderProduct> Products : 주문 상품 정보
// ProductSize : 주문상품 갯수 

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)
    {
        //성공처리 
    }

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

UMyStoveSDKObject::StoveSDKStartPurchase 함수가 정상적으로 처리되면 OnStartPurchase 콜백이 호출됩니다.
콜백에 전달되는 FStovePurchase 구조체에는 상품 구매에 대한 메타정보가 포함되어 있습니다.

  • FStovePurchase.TransactionMasterNo : 거래 고유 마스터 번호
  • FStovePurchase.TempPaymentUrl : 1회용 결제 URL
  • FStovePurchase.PurchaseProgress : 구매 진행 상태
    • 1 : 결제중 (TempPaymentUrl 을 이용하여 외부브라우저 표시 필요)
    • 2 : 구매 완료 (판매가격이 0 인 상품의 구매 진행으로 결제가 완료 상태로써 TempPaymentUrl 을 이용하여 외부브라우저 페이지 표시 불필요)

필요시 게임은 외부브라우저를 통해 1회용 결제 URL을 탐색합니다. 지원브라우저 : 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)
    {
        //구매완료 처리 (e.g. 구매완료 메세지 박스)
     }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

UMyStoveSDKObject::StoveSDKStartPurchase' 함수가 실행중에 오류가 발생하면 OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.
일반적으로 UMyStoveSDKObject::StoveSDKStartPurchase 함수 호출에 대해 OnError 콜백이 호출되면 게임은 실패에 대한 메세지를 게임 사용자에게 노출합니다.
아래 표는 게임 사용자에게 표시 할 메세지에 대한 가이드를 함께 제시합니다.

ExternalError 설명 게임 사용자 대상 노출 메시지 확인
500 Internal Server Error 일시적인 현상이거나 네트워크 원인으로 서비스가 원활하지 않습니다.
50001 상점이 존재하지 않거나, 점검 중 서비스 점검 중이거나, 존재하지 않는 서비스 입니다.
50002 상품이 존재 하지 않거나 판매 불가능 상품 상품 상태로 인하여 구매하실 수 없는 상품입니다.
50003 비 전시 상품 현재 판매하고 있지 않은 상품입니다.
50004 판매 기간이 아닌 상품 상품 판매 기간이 아닙니다.
50005 상품 가격이 불일치(상품 가격이 변경 되었을 경우) 상품 가격 정보가 변경되었습니다.
50009 구매 가능 한 회원 별 판매 개수를 초과 1인 당 구매 가능 개수를 초과 하였습니다.
50010 구매 가능 한 총 판매 개수를 초과 준비 된 수량이 모두 판매 완료 되었습니다.
50031 구매 수량이 '0' 구매하실 수량을 1개 이상 입력해 주세요.
999999 정의되지 않은 오류 기타 오류로 서비스가 원활하지 않습니다.

# 7) 상품 구매 상태 확인

UMyStoveSDKObject::StoveSDKConfirmPurchase 함수로 상품 구매 상태를 확인합니다.

// 입력 파라미터
// FString TransactionMasterNo : 거래 고유 마스터 번호(OnStartPurchase 콜백 파라미터 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)
    {
        // 성공 처리
    }

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

UMyStoveSDKObject::StoveSDKConfirmPurchase 함수가 정상적으로 처리되면 OnConfirmPurchase 콜백이 호출됩니다.
콜백에 전달되는 FStovePurchaseProduct 구조체에는 구매된 상품에 대한 메타정보가 포함되어 있고, status 콜백 파라미터는 상품 구매 상태를 전달합니다.

  • FStovePurchaseProduct.TotalQuantity : 상품 총 판매 수량
  • FStovePurchaseProduct.MemberQuantity : 회원 구매 수량
  • FStovePurchaseProduct.GuidQuantity : Guid 구매 수량(상품 구매 주체[CharacterNo/Guid/MemberNo]의 구매 수량)

별도의 게임서버가 없는 게임의 경우 구매 결과가 성공이라면 게임은 아이템을 지급할 수도 있습니다.
게임서버가 있는 게임의 경우 게임서버가 구매에 대한 알림을 받을 수 있고 이때 아이템을 지급할 수도 있습니다.

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

참고

위 샘플코드에서 함수에서 FString shopKeyStoveSDKIAPInit 함수로 호출하는 YOUR_SHOP_KEY와 동일한 값입니다.

shopKey를 입력 파라메터로 YOUR_SHOP_KEY를 보내야 합니다.

UMyStoveSDKObject::OnConfirmPurchase 함수가 실행중에 오류가 발생하면 OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
500 Internal Server Error
999999 정의되지 않은 오류

# 8) 상품 구매 이력 검증

UMyStoveSDKObject::StoveSDKVerifyPurchase 함수로 상품 구매 이력를 검증합니다.
1회 이상 구매 이력이 있는 상품의 경우 IsPurchased 필드 값은 true 입니다.
상품 구매 이력 검증은 PC SDK 내의 캐시를 대상으로 수행됩니다.
이때 CategoryId 파라미터의 값을 명시적으로 입력하면 해당 카테고리만을 대상으로 검색하고
CategoryId 파라미터의 값에 빈문자열("")을 입력하면 전체 카테고리를 대상으로 검색을 진행합니다.
따라서 검색할 카테고리 아이디를 정확히 입력하는 편이 검색 속도면에서 유리할 수 있습니다.

// 입력 파라미터
// const FString& CategoryId : 상품을 검색할 카테고리 아이디
// const FString& ProductId : 상품 아이디

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
    {
        //실패 처리 
    }

    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

UMyStoveSDKObject::StoveSDKVerifyPurchase 함수는 FStovePurchaseVerification 구조체를 리턴합니다.
리턴되는 FStovePurchaseVerification 구조체에는 상품 구매 이력 여부가 포함되어 있습니다.
또한, 함수 호출에 대한 에러코드도 포함되어 있습니다.

# 9) 보관함 조회

UMyStoveSDKObject::StoveSDKFetchInventory 함수로 보관함을 조회합니다.
보관함에는 구매가 완료된 상품들이 보관되어 있습니다.
보관함의 구매 완료 상품 리스트를 이용하여 상품 지급 처리를 할 수 있습니다.
보통 게임은 UMyStoveSDKObject::StoveSDKFetchInventory 함수를 호출하여 상품 구매 상태를 확인 후 즉시 상품을 지급하지만
오류, 게임 재설치 등의 사유로 지급된 상품 정보가 소실 되었을 경우 보관함 정보를 이용하여 복구 작업에 활용이 가능합니다.

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

    if (ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
    {
       //성공처리 
    }

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

UMyStoveSDKObject::StoveSDKFetchInventory 함수가 정상적으로 처리되면 OnFetchInventory 콜백이 호출됩니다.
콜백에 전달되는 FStoveInventoryItem 구조체에는 구매된 상품에 대한 메타정보가 포함되어 있습니다.

  • FStoveInventoryItem.TransactionMasterNo : 거래 고유 마스터 번호
  • FStoveInventoryItem.TransactionDetailNo : 거래 고유 상세 번호
  • FStoveInventoryItem.ProductId : 상품 아이디
  • FStoveInventoryItem.GameItemId : 상품 아이디에 매핑되는 게임 내 아이템 아이디
  • FStoveInventoryItem.ProductName : 상품명
  • FStoveInventoryItem.Quantity : 개별 상품 수량
  • FStoveInventoryItem.ThumbnailUrl : 대표 상품 이미지
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

UMyStoveSDKObject::StoveSDKFetchInventory 함수가 실행중에 오류가 발생하면 OnError 콜백이 호출됩니다.
FStoveError 구조체의 ExternalError 필드를 통해 외부 오류를 확인할 수 있습니다.

ExternalError 설명
500 Internal Server Error
999999 정의되지 않은 오류

# 부가서비스 연동하기

PC SDK는 부가서비스를 게임에 통합할 수 있도록 API를 제공합니다.
PC SDK가 지원하는 부가서비스로는 사용자정의 이벤트 로그, PC SDK 버전 조회, 과몰입방지 알림, 셧다운 알림, 추적단서 조회가 있습니다.
게임은 게임내 사용자정의 이벤트(게임 로그)를 스토브 플랫폼으로 전송할 수 있습니다. 또한 게임은 현재 사용중인 PC SDK의 유의적 버전을 조회할 수 있습니다.
PC SDK의 유의적 버전 조회는 콜백이 아닌 리턴값으로 획득이 가능합니다.
과몰입방지 알림은 매시간 게임 과몰입에 대한 경고 문구를 콜백을 통해 전달합니다.
셧다운 알림은 만 18세 미만의 청소년이 부모에 의해 요일별 특정시간에 게임을 이용 할 수 없도록 제한을 하는 시스템으로써 요건이 충족되면 최대 4회에 걸쳐 알림을 콜백을 통해 전달합니다.

# 1) Callback 설정

부가서비스 API를 사용하여 PC SDK와 커뮤니케이션 하기 위하여, 게임에서는 아래 UMyStovePCSDKObject 클래스의 연결된 콜백함수를 재정의해야 합니다.

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;

    // FetchTermsAgreement 처리가 완료됐을 때 호출되는 콜백
  void OnFetchTermsAgreement(FStoveFetchTermsAgreement TermsAgreement) final;
    
    
    //StashCustomEvent 처리가 완료됐을 때 호출되는 콜백
    void OnStashCustomEvent(FStoveCustomEvent CustomEvent, int ParameterSize, FStoveCustomEventParameter* Parameters) final;
    
    // ADD 2.6.0 Start
    // 과몰입방지를 위해 매시간 호출되는 콜백
    void OnOverImmersion(FStoveOverImmersion OverImmersion) final;
    
    // 셧다운 제한시 호출되는 콜백
    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
27
28
29

연동하기 1) Config, Callback 설정에서와 같이 UStoveSDKObject를 상속받은 'UMyStoveSDKObject'클래스의 콜백함수를 재정의하여 이벤트를 연결합니다.

/*소유권(Ownership) 기능만 사용하는 경우는,
필수 구현 콜백인 OnError, OnInitComplete외에
OnOwnership 콜백만 추가로 구현해서 연결합니다.*/
void UMyStoveSDKObject::OnInitComplete()
{
      // 초기화 성공 후 처리내용
}
 
void UMyStoveSDKObject::OnError(FStoveError Error)
{
      // 에러에 대한 처리내용
}
 
void UMyStoveSDKObject::OnOwnership(int Size, FStoveOwnership* Ownerships)
{
       // 소유권 조회 후 처리내용
}
void UMyStoveSDKObject::OnStashCustomEvent(FStoveCustomEvent CustomEvent, int ParameterSize, FStoveCustomEventParameter* Parameters)
{
       // 로그전송 후 전달된 내용 확인
}
// ADD 2.6.0 Start
void UMyStoveSDKObject::OnOverImmersion(FStoveOverImmersion OverImmersion)
{
       //  과몰입방지를 위해 매시간 호출되는 콜백 
}

void UMyStoveSDKObject::OnShutdown(FStoveShutdown Shutdown)
{
       // 법률에 의거 선택적 셧다운이 필요한 경우 구현 합니다. 
}
// 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

OnStashCustomEvent, OnOverImmersion, OnShutdown 콜백을 반드시 구현할 필요는 없습니다. 게임에서 사용자정의 이벤트 로그 기능을 사용할 경우만 연결하면 됩니다.

경고

OnOverImmersion 콜백은 법률에 의거 게임과몰입/중독 예방조치가 필요한 경우 반드시 구현하여야 합니다. OnShutdown 콜백은 법률에 의거 선택적 셧다운이 필요한 경우 반드시 구현하여야 합니다.

# 2) 사용자정의 이벤트 로깅

UMyStoveSDKObject::StoveSDKStashCustomEvent 함수로 사용자정의 이벤트(게임 로그)를 로깅합니다.

// 입력 파라미터
// const FString& Name: 이벤트명
// const FString& Category1 : 1차 카테고리명
// const FString& Category2 : 2차 카테고리명
// const FString& SimpleValue : 간단한 값
// const TArray<FStoveCustomEventParameter> Params : 세부적인 파라미터 정보
// int paramsSize : 세부적인 파라미터 정보 개수
FStoveResult ErrorResult = UMyStoveSDKObject::StoveSDKStashCustomEvent("EVENT_NAME", "CATEGORY1", "CATEGORY2", 1.0f, params, PARAMS_SIZE);
if(ErrorResult.Result == StovePCResult::STOVE_PC_NO_ERROR)
{
    /* 성공 처리 */
}
1
2
3
4
5
6
7
8
9
10
11
12

StoveSDKStashCustomEvent 함수가 정상적으로 처리되면 OnStashCustomEvent 콜백이 호출됩니다.
콜백에 전달되는 FStoveCustomEvent 구조체에는 API 호출시 전달한 이벤트명, 1차 카테고리명, 2차 카테고리명, 간단한 값이 포함되어 있습니다.
콜백에 전달되는 FStoveCustomEventParameter 구조체에는 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

주의사항

콜백파라미터 FStoveCustomEvent/FStoveCustomEventParameter 구조체의 유효한 범위는 콜백함수 스코프로 한정됩니다.
PC SDK는 콜백함수 실행이 완료되는 즉시 내부에서 할당한 메모리를 해제합니다.
따라서 콜백함수 스코프 밖에서 FStoveCustomEvent/FStoveCustomEventParameter 구조체의 정보를 사용하기 위해 저장이 필요한 경우 반드시 깊은복사(Deep Copy)를 통해 사본을 생성하고,
사본에 대한 사용이 완료되면 메모리를 해제하여야 합니다.

# 3) PC SDK 유의적 버전 얻기

UMyStoveSDKObject::GetSDKVersion 함수로 현재 연동중인 PC SDK의 버전 정보를 조회합니다.

FString Version = UMyStoveSDKObject::StoveSDKGetSDKVersion();
if (Version.IsEmpty() == false)
{
    /* 성공 처리 */
}
1
2
3
4
5

# 4) 게임 과몰입방지 2.6.0

게임을 시작한 후 매시간마다 OnOverImmersion 콜백이 호출됩니다.
콜백에 전달되는 FStoveOverImmersion 구조체에는 메세지, 게임이용 경과시간, 메세지 최소 노출시간(초)이 포함되어 있습니다.
메세지는 PC SDK에 설정된 언어를 기반으로 번역된 메세지가 전달 됩니다.

  • FStoveOverImmersion.Message : 과몰입 메세지
  • FStoveOverImmersion.ElapsedTimeInHours : 경과 시간
  • FStoveOverImmersion.MinExposureTimeInSeconds : 메세지 최소 노출 시간(초단위)
void UMyStoveSDKObject::OnOverImmersion(FStoveOverImmersion OverImmersion)
{
    OnLog("[OverImmersion]");
 
    OnLog("- Message : %s", *(OverImmersion.Message));
    OnLog("- ElapsedTimeInHours : %d", OverImmersion.ElapsedTimeInHours);
    OnLog("- MinExposureTimeInSeconds : %d", OverImmersion.MinExposureTimeInSeconds);  
    // 게임에서 과몰입 방지에 대한 안내
}
1
2
3
4
5
6
7
8
9

과몰입 메시지 안내

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

# 5) 셧다운 2.6.0

게임을 시작한 후 선택적 셧다운 대상자에 한해 셧다운 시스템에 등록된 타임테이블에 의거하여 OnShutdown 콜백이 호출됩니다.
OnShutdown 콜백은 최대 4회 호출 될 수 있으며 호출되는 시점 및 게임에서 조치해야 하는 사항은 아래와 같습니다.

  • PCSDK 초기화 성공 후 셧다운 이벤트
    • 10분전 셧다운 알림 : 10분뒤 로그아웃 된다는 알림만 표시
    • 5분전 셧다운 알림 : 5분뒤 로그아웃 된다는 알림만 표시
    • 1분전 셧다운 알림 : 1분뒤 로그아웃 된다는 알림만 표시
    • 셧다운 알림 : 로그아웃 된다는 알림을 표시하고 사용자 확인시 즉시 게임 종료

콜백에 전달되는 FStoveShutdown 구조체에는 셧다운까지 남은 시간, 메세지, 메세지 노출시간(초)이 포함되어 있습니다.

  • FStoveShutdown.InadvanceTimeInMinutes : 사용자의 셧다운까지 남은 시간(분)으로써 0 인 경우 즉시 게임 종료
  • FStoveShutdown.Message : 셧다운 알림 메세지
  • FStoveShutdown.ExposureTimeInSeconds : 메세지 노출 시간(초)
void UMyStoveSDKObject::OnShutdown(const FStoveShutdown Shutdown)
{
    //셧다운 정보 출력
    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

주의사항

콜백파라미터 FStoveShutdown 구조체의 유효한 범위는 콜백함수 스코프로 한정됩니다.
PC SDK는 콜백함수 실행이 완료되는 즉시 내부에서 할당한 메모리를 해제합니다.
따라서 콜백함수 스코프 밖에서 FStoveShutdown 구조체의 정보를 사용하기 위해 저장이 필요한 경우 반드시 깊은복사(Deep Copy)를 통해 사본을 생성하고,
사본에 대한 사용이 완료되면 메모리를 해제하여야 합니다.

셧다운 메시지 안내

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

# 6) 추적 단서 조회

UMyStoveSDKObject::StoveSDKGetTraceHint 함수로 스토브 플랫폼 로그를 추적 하기 위한 일련의 단서를 조회합니다.

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
{
    /* 실패 처리 */
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

UStoveSDKObject::StoveSDKGetTraceHint 함수는 FStoveTraceHint 구조체를 리턴합니다.
리턴되는 FStoveTraceHint 구조체에는 세션 아이디 및 레퍼런스 세션 아이디 등이 포함되어 있습니다.
또한, 함수 호출에 대한 에러코드도 포함되어 있습니다.

# 언리얼 플러그인 업데이트

기존에 연동했던 언리얼 플러그인을 새로운 버전을 업데이트 하기 위한 가이드 입니다. StoveSDKPluing.uplugin 파일의 현재 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

현재의 버전을 확인 후 업데이트 하려는 최신버전을 다운로드 받습니다. 다운로드 받은 후 압축을 풀면 Plugins 폴더가 생성됩니다.

Figure1

최신버전의 Pluings 폴더를 복사하여 게임엔진내의 Plugins 폴더를 복사 덮어쓰기 합니다.

게임에 연동된 Plugins 폴더에는 타사 플러그인도 포함될 수 있으니 StoveSDKPlugin 만 덮어쓰기 합니다.

덮어쓰기가 완료되었다면 게임프로젝트에서 현재사용하고 있는 .uproject 마우스 우측버튼 메뉴에서 언리얼 엔진 버전에 따라 재빌드 합니다.

Figure1

언리얼 v2.6.0 이상 업그레이드시

  • v2.6.0 부터 언리얼 코딩컨밴션에 따라 함수인자, 구조체필드, 등의 철자가 변경 되었으므로 최신 가이드의 코딩컨밴션을 확인하시기 바랍니다.
  • PCSDK v2.0 대 버전인 경우 위 가이드로 업데이트 가능함
Last Updated: 2024. 7. 16. 오후 4:07:47