Documentation index for AI agents

GS2-SerialKey SDK for Game Engine API 레퍼런스

게임 엔진용 GS2-SerialKey SDK의 모델 사양과 API 레퍼런스

모델

EzSerialKey

시리얼 코드

발급된 시리얼 코드는 한 번만 사용할 수 있습니다.
시리얼 코드는 “RPCLP-FP7N-NCDMJ-FLVA-IRI4"와 같은 형식으로 발급되며 데이터 길이는 변경할 수 없습니다.
시리얼 코드 내에는 캠페인 종류에 대한 정보도 포함되어 있으며, 시리얼 코드를 사용할 때는 네임스페이스만 지정하면 사용할 수 있습니다.

타입활성화 조건필수기본값값 제한설명
campaignModelNamestring
~ 128자캠페인 이름
이 시리얼 코드가 속한 캠페인 모델의 이름입니다. 캠페인 정보는 시리얼 코드 자체에 포함되어 있으므로 코드를 사용할 때는 네임스페이스만 지정하면 됩니다.
metadatastring~ 2048자메타데이터
메타데이터에는 임의의 값을 설정할 수 있습니다.
이 값들은 GS2의 동작에는 영향을 주지 않으므로, 게임 내에서 사용하는 정보를 저장하는 용도로 사용할 수 있습니다.
codestring
~ 48자시리얼 코드
“XXXXX-XXXX-XXXXX-XXXX-XXXX” 형식의 시리얼 코드 문자열입니다. 각 코드는 고유하며 캠페인 식별 정보를 포함합니다. 코드의 형식과 데이터 길이는 고정되어 있어 변경할 수 없습니다.
status문자열 열거형
enum {
  “ACTIVE”,
  “USED”,
  “INACTIVE”
}
“ACTIVE”상태
이 시리얼 코드의 현재 사용 상태입니다. 사용자가 소비하면 ACTIVE에서 USED로 전환됩니다. 이중 사용을 방지하기 위해 낙관적 잠금(optimistic locking)으로 보호됩니다. INACTIVE 상태의 코드는 사용할 수 없습니다.
정의설명
ACTIVE사용 가능
USED사용됨
INACTIVE비활성(사용 불가)

EzCampaignModel

캠페인 모델

캠페인 모델은 캠페인을 정의하고 시리얼 코드와 연결하여 관리하는 데 사용됩니다.

타입활성화 조건필수기본값값 제한설명
namestring
~ 128자캠페인 모델 이름
metadatastring~ 2048자메타데이터
메타데이터에는 임의의 값을 설정할 수 있습니다.
이 값들은 GS2의 동작에는 영향을 주지 않으므로, 게임 내에서 사용하는 정보를 저장하는 용도로 사용할 수 있습니다.
enableCampaignCodeboolfalse캠페인 코드에 의한 교환을 허용할지 여부
활성화하면 개별 시리얼 코드가 아닌 공통 캠페인 코드(캠페인 이름)를 사용하여 보상을 교환할 수 있게 됩니다. 이를 통해 하나의 코드를 여러 사용자가 사용할 수 있습니다.

메서드

getCampaignModel

특정 시리얼 코드 캠페인의 상세 정보 조회

캠페인 이름을 지정하여 설정을 포함한 상세 정보를 조회합니다.

캠페인 모델은 동일한 목적과 설정을 공유하는 시리얼 코드의 그룹을 정의합니다.
예를 들어 “출시 기념 코드”, “잡지 프로모션 코드”, “이벤트 배포 코드” 등을 각각 별도의 캠페인으로 관리할 수 있습니다.

응답에는 다음이 포함됩니다:

  • 캠페인 이름과 메타데이터
  • 캠페인이 현재 활성화되어 코드 교환을 허용하고 있는지 여부

코드 입력 화면을 표시하기 전에 캠페인의 상세 정보를 확인할 때 사용합니다. 예를 들어 플레이어에게 시리얼 코드를 입력하게 하기 전에 캠페인이 활성화되어 있는지 확인할 수 있습니다.

Request

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
campaignModelNamestring
~ 128자캠페인 모델 이름

Result

타입설명
itemEzCampaignModel캠페인 모델

구현 예제

    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).CampaignModel(
        campaignModelName: "campaign-0001"
    );
    var item = await domain.ModelAsync();
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).CampaignModel(
        campaignModelName: "campaign-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->CampaignModel(
        "campaign-0001" // campaignModelName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).campaign_model(
        "campaign-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result
값 변경 이벤트 핸들링
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).CampaignModel(
        campaignModelName: "campaign-0001"
    );

    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).CampaignModel(
        campaignModelName: "campaign-0001"
    );

    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);
    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->CampaignModel(
        "campaign-0001" // campaignModelName
    );

    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::SerialKey::Model::FCampaignModel> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);
var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).campaign_model(
        "campaign-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

get

시리얼 코드의 상태 확인

특정 시리얼 코드의 상세 정보를 조회합니다. 사용 여부, 어떤 캠페인에 속하는지 등의 정보가 포함됩니다.

코드를 교환하기 전후에 상태를 확인할 때 사용합니다. 예를 들어:

  • 플레이어가 이미 사용된 코드를 입력했을 때 “이 코드는 이미 사용되었습니다"라고 표시
  • 플레이어가 교환을 확정하기 전에 캠페인 정보(코드로 얻을 수 있는 보상)를 표시
  • 고객 지원 목적으로 코드를 조회

코드는 “XXXXX-XXXX-XXXXX-XXXX-XXXXX"와 같은 형식입니다.
응답에는 시리얼 코드의 상세 정보와 관련된 캠페인 모델이 포함됩니다.

Request

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
codestring
~ 48자시리얼 코드
“XXXXX-XXXX-XXXXX-XXXX-XXXX” 형식의 시리얼 코드 문자열입니다. 각 코드는 고유하며 캠페인 식별 정보를 포함합니다. 코드의 형식과 데이터 길이는 고정되어 있어 변경할 수 없습니다.

Result

타입설명
itemEzSerialKey시리얼 코드
campaignModelEzCampaignModel캠페인 모델

구현 예제

    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).SerialKey(
        serialKeyCode: "code-0001"
    );
    var item = await domain.ModelAsync();
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).SerialKey(
        serialKeyCode: "code-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->SerialKey(
        "code-0001" // serialKeyCode
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).serial_key(
        "code-0001"
    )

var async_result = await domain.model()
if async_result.error != null:
    push_error(str(async_result.error))
    return

var result = async_result.result
값 변경 이벤트 핸들링
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).SerialKey(
        serialKeyCode: "code-0001"
    );

    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).User(
        userId: "user-0001"
    ).SerialKey(
        serialKeyCode: "code-0001"
    );

    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);
    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->User(
        "user-0001" // userId
    )->SerialKey(
        "code-0001" // serialKeyCode
    );

    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::SerialKey::Model::FSerialKey> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);
var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).user(
        "user-0001"
    ).serial_key(
        "code-0001"
    )

# 이벤트 핸들링 시작
var callback_id = domain.subscribe_model(func(value):
    # 값이 변화했을 때 호출됨
    # value에는 변경 후의 값이 전달됩니다
    pass
)

# 이벤트 핸들링 정지
domain.unsubscribe_model(callback_id)

useSerialCode

시리얼 코드 교환

시리얼 코드를 사용(소비)하여 현재 플레이어가 교환한 것으로 표시합니다.
한 번 사용된 코드는 누구도 다시 사용할 수 없습니다.

게임 내 “시리얼 코드 입력” 기능에서 사용하는 메인 API입니다. 일반적인 흐름은 다음과 같습니다:

  1. 플레이어가 게임 내 “코드 교환” 화면을 연다
  2. 플레이어가 시리얼 코드를 입력한다(프로모션 카드, 이메일, 웹사이트 등에서 얻은 것)
  3. 게임이 입력된 코드로 UseSerialCode를 호출한다
  4. 성공하면 코드가 사용됨 상태가 된다 — 보상 지급 시스템과 조합하여 플레이어에게 보상을 지급한다
  5. 코드가 이미 사용된 경우 “사용됨” 오류가 반환된다
  6. 코드가 존재하지 않는 경우 “코드를 찾을 수 없음” 오류가 반환된다

주요 사용 사례:

  • 상품이나 잡지에 동봉되는 프로모션 코드
  • 이벤트나 SNS를 통해 배포되는 기프트 코드
  • 사전 등록 특전 코드
  • 콜라보레이션 캠페인 코드

Request

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
gameSessionGameSession
GameSession
codestring
~ 48자시리얼 코드
“XXXXX-XXXX-XXXXX-XXXX-XXXX” 형식의 시리얼 코드 문자열입니다. 각 코드는 고유하며 캠페인 식별 정보를 포함합니다. 코드의 형식과 데이터 길이는 고정되어 있어 변경할 수 없습니다.

Result

타입설명
itemEzSerialKey시리얼 코드
campaignModelEzCampaignModel캠페인 모델

Error

이 API에는 특별한 예외가 정의되어 있습니다.
GS2-SDK for Game Engine에서는 게임 내에서 핸들링이 필요할 것으로 예상되는 에러를, 일반적인 예외에서 파생된 특수화된 예외로 제공하여 다루기 쉽게 하고 있습니다.
일반적인 에러의 종류와 핸들링 방법은 여기 문서를 참고해 주세요.

타입베이스 클래스설명
AlreadyUsedExceptionBadRequestException지정된 시리얼 코드는 이미 사용되었습니다
CodeNotFoundExceptionNotFoundException지정된 시리얼 코드는 존재하지 않습니다

구현 예제

try {
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SerialKey(
        serialKeyCode: "code-0001"
    );
    var result = await domain.UseSerialCodeAsync(
        code: "code-0001"
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2SerialKey.Exception.AlreadyUsedException e) {
    // The specified serial code has already been used.
} catch(Gs2.Gs2SerialKey.Exception.CodeNotFoundException e) {
    // The specified serial code does not exist.
}
    var domain = gs2.SerialKey.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).SerialKey(
        serialKeyCode: "code-0001"
    );
    var future = domain.UseSerialCodeFuture(
        code: "code-0001"
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2SerialKey.Exception.AlreadyUsedException)
        {
            // The specified serial code has already been used.
        }
        if (future.Error is Gs2.Gs2SerialKey.Exception.CodeNotFoundException)
        {
            // The specified serial code does not exist.
        }
        onError.Invoke(future.Error, null);
        yield break;
    }
    var future2 = future.Result.ModelFuture();
    yield return future2;
    if (future2.Error != null)
    {
        onError.Invoke(future2.Error, null);
        yield break;
    }
    var result = future2.Result;
    const auto Domain = Gs2->SerialKey->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->SerialKey(
        "code-0001" // serialKeyCode
    );
    const auto Future = Domain->UseSerialCode(
        "code-0001" // code
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::SerialKey::Error::FAlreadyUsedError::Class))
        {
            // The specified serial code has already been used.
        }
        if (e->IsChildOf(Gs2::SerialKey::Error::FCodeNotFoundError::Class))
        {
            // The specified serial code does not exist.
        }
        return false;
    }

    // 변경된 값 / 결과 값을 취득
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();
var domain = ez.serial_key.namespace_(
        "namespace-0001"
    ).me(game_session).serial_key(
        "code-0001"
    )

var async_result = await domain.use_serial_code(
    "code-0001" # code
)
if async_result.error != null:
    if async_result.error is Gs2SerialKeyAlreadyUsedException:
        # 지정된 시리얼 코드는 이미 사용되었습니다
        pass
    if async_result.error is Gs2SerialKeyCodeNotFoundException:
        # 지정된 시리얼 코드는 존재하지 않습니다
        pass
    push_error(str(async_result.error))
    return

var result = async_result.result