Documentation index for AI agents

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

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

모델

EzWallet

지갑

지갑 내 통화는 유료로 구매한 통화와 무료로 얻은 통화로 크게 나누어 관리됩니다.
유료로 구매한 통화는 다시 구매 시점의 단가별로 관리되어, 서비스가 종료되었을 때의 환불이나 자금결제법에 해당하는 잔액이 존재하는지를 집계할 수 있습니다.

지갑에는 슬롯이 있으며, 슬롯마다 서로 다른 잔액을 관리할 수 있습니다.
플랫폼 간에 잔액을 공유할 수 없는 경우에는 플랫폼마다 다른 슬롯을 사용함으로써 나누어 관리할 수 있습니다.
이때 무료로 얻은 통화는 모든 플랫폼에서 공통된 값을 사용할 수도 있습니다.

타입활성화 조건필수기본값값 제한설명
slotint
0 ~ 100000000슬롯 번호
플랫폼이나 컨텍스트별로 지갑 잔액을 분리하기 위한 식별자입니다.
슬롯을 달리하면 서로 다른 유료 통화 풀을 관리할 수 있습니다(예: iOS 구매는 슬롯 0, Android는 슬롯 1).
무료 통화는 네임스페이스의 shareFree 설정에 따라 모든 슬롯 간에 공유할 수도 있습니다.
paidint00 ~ 2147483646유료 통화 보유량
이 지갑 슬롯 내 유료(구매한) 통화의 합계량입니다.
단가가 0이 아닌 모든 WalletDetail 항목의 합계입니다.
스토어 구매를 통한 충전으로 증가하고, 소비 우선순위에 따라 소비되어 감소합니다.
freeint00 ~ 2147483646무료 통화 보유량
이 지갑 슬롯 내 무료(지급된) 통화의 합계량입니다.
단가가 0인 WalletDetail 항목에 해당합니다.
네임스페이스에서 shareFree가 활성화된 경우, 이 값은 슬롯 0에서 모든 지갑 슬롯으로 동기화됩니다.
shareFreeboolfalse무상 통화 공유
이 지갑의 무상 통화가 모든 슬롯 간에 공유되는지 여부입니다.
이 값은 지갑 생성 시 네임스페이스 설정에서 상속됩니다.
true인 경우, 무상 통화가 슬롯 0에서 다른 모든 지갑 슬롯으로 동기화됩니다.
updatedAtlong
현재 시각최종 갱신일시
UNIX 시간・밀리초
※ 서버가 자동으로 설정

메서드

get

플레이어의 유료 통화 지갑 잔액을 취득한다

지정한 슬롯의 플레이어 지갑을 취득하여 유료 통화와 무료 통화 각각의 현재 잔액을 확인할 수 있습니다.
“유료” 통화는 플레이어가 실제 돈으로 구매한 것(예: 100 젬을 ¥120에 구매)이고, “무료” 통화는 게임 플레이를 통해 획득한 것(예: 이벤트 보상, 로그인 보너스)입니다.
일부 기능에서는 유료 통화만을 요구하는 경우가 있기 때문에(예: 특정 가챠나 특별 오퍼) 별도로 관리됩니다.
플레이어의 통화 잔액을 표시하는 데 사용합니다. 예를 들어 상점 화면이나 헤더 UI에서 “젬: 350(유료: 100, 무료: 250)“과 같이 표시하는 데 유용합니다.

Request

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
gameSessionGameSession
GameSession
slotint
0 ~ 100000000슬롯 번호
플랫폼이나 컨텍스트별로 지갑 잔액을 분리하기 위한 식별자입니다.
슬롯을 달리하면 서로 다른 유료 통화 풀을 관리할 수 있습니다(예: iOS 구매는 슬롯 0, Android는 슬롯 1).
무료 통화는 네임스페이스의 shareFree 설정에 따라 모든 슬롯 간에 공유할 수도 있습니다.

Result

타입설명
itemEzWallet지갑

구현 예제

    var domain = gs2.Money.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    var item = await domain.ModelAsync();
    var domain = gs2.Money.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->Money->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Wallet(
        0 // slot
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
var domain = ez.money.namespace_(
        "namespace-0001"
    ).me(game_session).wallet(
        0
    )

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.Money.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);
    var domain = gs2.Money.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    
    // 이벤트 핸들링 시작
    var callbackId = domain.Subscribe(
        value => {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    domain.Unsubscribe(callbackId);
    const auto Domain = Gs2->Money->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Wallet(
        0 // slot
    );
    
    // 이벤트 핸들링 시작
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Money::Model::FWallet> value) {
            // 값이 변화했을 때 호출됨
            // value에는 변경 후의 값이 전달됨
        }
    );

    // 이벤트 핸들링 정지
    Domain->Unsubscribe(CallbackId);
var domain = ez.money.namespace_(
        "namespace-0001"
    ).me(game_session).wallet(
        0
    )

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

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

withdraw

플레이어의 지갑에서 유료 통화 소비하기

플레이어의 지갑에서 지정된 수량의 유료 통화를 차감합니다.
기본값(paidOnly = false)에서는 무료 통화가 먼저 소비되고, 부족한 만큼 유료 통화가 소비됩니다. 이를 통해 플레이어는 구매한 통화를 사용하기 전에 무료 통화를 모두 소진할 수 있습니다.
paidOnly를 true로 설정하면 유료 통화만 소비됩니다. 법률상 유료 통화만 사용해야 하는 기능(예: 일부 지역의 유료 전용 가챠)에 필요합니다.
플레이어가 유료 통화로 구매할 때 사용합니다. 예를 들어 특별한 아이템을 구매하거나 가챠를 뽑기 위해 젬 100개를 소비하는 경우입니다.
참고: GS2-Showcase를 통한 상품 구매의 대가로 통화를 소비하는 경우에는 자동으로 처리되므로, 이 API를 호출할 필요가 없습니다.

Request

타입활성화 조건필수기본값값 제한설명
namespaceNamestring
~ 128자네임스페이스 이름
네임스페이스 고유의 이름입니다. 영숫자 및 -(하이픈) _(언더스코어) .(마침표)로 지정합니다.
gameSessionGameSession
GameSession
slotint
0 ~ 100000000슬롯 번호
플랫폼이나 컨텍스트별로 지갑 잔액을 분리하기 위한 식별자입니다.
슬롯을 달리하면 서로 다른 유료 통화 풀을 관리할 수 있습니다(예: iOS 구매는 슬롯 0, Android는 슬롯 1).
무료 통화는 네임스페이스의 shareFree 설정에 따라 모든 슬롯 간에 공유할 수도 있습니다.
countint
1 ~ 2147483646소비할 유료 통화 수량
paidOnlyboolfalse유료 통화만을 대상으로 할지 여부

Result

타입설명
itemEzWallet소비 후 지갑
pricefloat소비한 통화의 가격

Error

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

타입베이스 클래스설명
ConflictExceptionConflictException지갑 조작 처리가 충돌했습니다. 재시도가 필요합니다
InsufficientExceptionBadRequestException지갑의 잔액이 부족합니다

구현 예제

try {
    var domain = gs2.Money.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    var result = await domain.WithdrawAsync(
        count: 50,
        paidOnly: null
    );
    var item = await result.ModelAsync();
    var price = result.Price;
} catch(Gs2.Gs2Money.Exception.ConflictException e) {
    // The wallet operation process conflicted. Retry required.
} catch(Gs2.Gs2Money.Exception.InsufficientException e) {
    // Wallet balance is insufficient.
}
    var domain = gs2.Money.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Wallet(
        slot: 0
    );
    var future = domain.WithdrawFuture(
        count: 50,
        paidOnly: null
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Money.Exception.ConflictException)
        {
            // The wallet operation process conflicted. Retry required.
        }
        if (future.Error is Gs2.Gs2Money.Exception.InsufficientException)
        {
            // Wallet balance is insufficient.
        }
        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;
    var price = future.Result.Price;
    const auto Domain = Gs2->Money->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Wallet(
        0 // slot
    );
    const auto Future = Domain->Withdraw(
        50 // count
        // paidOnly
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Money::Error::FConflictError::Class))
        {
            // The wallet operation process conflicted. Retry required.
        }
        if (e->IsChildOf(Gs2::Money::Error::FInsufficientError::Class))
        {
            // Wallet balance is insufficient.
        }
        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();
    const auto Price = Result->Price;
var domain = ez.money.namespace_(
        "namespace-0001"
    ).me(game_session).wallet(
        0
    )

var async_result = await domain.withdraw(
    50, # count
    null # paid_only
)
if async_result.error != null:
    if async_result.error is Gs2MoneyConflictException:
        # 지갑 조작 처리가 충돌했습니다. 재시도가 필요합니다
        pass
    if async_result.error is Gs2MoneyInsufficientException:
        # 지갑의 잔액이 부족합니다
        pass
    push_error(str(async_result.error))
    return

var result = async_result.result