GS2-Limit SDK for Game Engine API Reference

Specifications of models and API references for GS2-Limit SDK for Game Engine

Model

EzCounter

Current Counter Value

Tracks the current usage count for a specific counter under a limit model for each user. Multiple counters can exist under a single limit model (e.g., one counter per quest for one-time rewards). The count is compared against a maximum value specified at the time of the count-up operation, and is automatically reset to zero based on the limit model’s reset schedule.

TypeConditionRequiredDefaultValue LimitsDescription
counterIdstring
*
~ 1024 charsCounter GRN
* Set automatically by the server
limitNamestring
~ 128 charsUsage Limit Model Name
The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value.
namestring
~ 128 charsCounter Name
A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models.
countint00 ~ 2147483646Count Value
The current usage count for this counter. Incremented by the countUp operation and compared against the maximum value specified at that time. Automatically reset to zero when the limit model’s reset timing is reached.
createdAtlong
*
NowDatetime of creation
Unix time, milliseconds
* Set automatically by the server
updatedAtlong
*
NowDatetime of last update
Unix time, milliseconds
* Set automatically by the server

EzLimitModel

Usage Limit Model

Usage Limit Model allows you to set the timing for resetting the usage count. The reset interval can be selected from five options: “Daily”, “Weekly”, “Monthly”, “Every fixed number of days” or “Not Reset”.

Additionally, the maximum value for usage Limits is not fixed in the master data. This design allows the maximum allowed count to be changed dynamically depending on the game context. For example, in a step-up gacha:

  • Items purchasable when the purchase counter is under 3
  • When the above items are unavailable, another item purchasable if the purchase counter is under 5

The design assumes the ability to switch the “maximum count” based on the situation.

TypeConditionRequiredDefaultValue LimitsDescription
limitModelIdstring
*
~ 1024 charsUsage Limit Model GRN
* Set automatically by the server
namestring
~ 128 charsUsage Limit Model name
Usage Limit Model-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
metadatastring~ 2048 charsMetadata
Arbitrary values can be set in the metadata.
Since they do not affect GS2’s behavior, they can be used to store information used in the game.
resetTypeString Enum
enum {
  “notReset”,
  “daily”,
  “weekly”,
  “monthly”,
  “days”
}
Reset Timing
Determines when the counter values under this limit model are automatically reset to zero. Choose from: notReset (permanent, never resets), daily (resets at the specified hour each day), weekly (resets on the specified day of the week), monthly (resets on the specified day of the month), or days (resets every fixed number of days from an anchor timestamp). All times are in UTC.
DefinitionDescription
“notReset”Not Reset
“daily”Daily
“weekly”Weekly
“monthly”Monthly
“days”Every fixed number of days
resetDayOfMonthint{resetType} == “monthly”
✓*
1 ~ 31Reset Day of Month
The day of the month on which counters are reset when resetType is “monthly”. Valid values are 1-31. If the specified day exceeds the number of days in the current month (e.g., 31 for February), the counter resets on the last day of that month.

* Required if resetType is “monthly”
resetDayOfWeekString Enum
enum {
  “sunday”,
  “monday”,
  “tuesday”,
  “wednesday”,
  “thursday”,
  “friday”,
  “saturday”
}
{resetType} == “weekly”
✓*
Reset Day of Week
The day of the week on which counters are reset when resetType is “weekly”. The reset occurs at the hour specified by resetHour (UTC) on this day.
DefinitionDescription
“sunday”Sunday
“monday”Monday
“tuesday”Tuesday
“wednesday”Wednesday
“thursday”Thursday
“friday”Friday
“saturday”Saturday

* Required if resetType is “weekly”
resetHourint{resetType} in [“monthly”, “weekly”, “daily”]
✓*
0 ~ 23Reset Hour
The hour (0-23) in UTC at which counters are reset for daily, weekly, or monthly reset types. For example, a value of 0 means counters reset at midnight UTC.

* Required if resetType is “monthly”,“weekly”,“daily”
anchorTimestamplong{resetType} == “days”
✓*
Base date and time for counting elapsed days
Unix time, milliseconds

* Required if resetType is “days”
daysint{resetType} == “days”
✓*
1 ~ 2147483646Number of Days to Reset
The interval in days between counter resets when resetType is “days”. The reset cycle is calculated from the anchorTimestamp. For example, if days is 7 and anchorTimestamp is Monday at noon, counters reset every Monday at noon.

* Required if resetType is “days”

Methods

countUp

Increment a usage limit counter

Increases the specified counter by the given amount. If the counter would exceed the maximum value, the operation fails — this is how the usage limit is enforced. For example, if a daily purchase limit is set to 3 and the player has already purchased twice, counting up by 1 succeeds (total: 3). But trying to count up again would fail because it would exceed the limit. You can specify both the increment amount (countUpValue) and the maximum allowed value (maxValue). Use this when the player performs a limited action — for example, when they make a daily shop purchase or enter a limited dungeon. If the count up fails, it means the player has reached their limit.

Request

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
limitNamestring
~ 128 charsUsage Limit Model Name
The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value.
counterNamestring
~ 128 charsCounter Name
A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models.
gameSessionGameSession
GameSession
countUpValueint11 ~ 2147483646Amount to count up
maxValueint1 ~ 2147483646Maximum value allowed to count up

Result

TypeDescription
itemEzCounterCounter with increased count

Error

Special exceptions are defined in this API. GS2-SDK for GameEngine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games. Please refer to the documentation here for more information on common error types and handling methods.

TypeBase TypeDescription
OverflowExceptionBadRequestExceptionThe maximum number of times limit has been reached.

Implementation Example

try {
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Counter(
        limitName: "daily",
        counterName: "counter1"
    );
    var result = await domain.CountUpAsync(
        countUpValue: 1,
        maxValue: 100
    );
    var item = await result.ModelAsync();
} catch(Gs2.Gs2Limit.Exception.OverflowException e) {
    // The maximum number of times limit has been reached.
}
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Counter(
        limitName: "daily",
        counterName: "counter1"
    );
    var future = domain.CountUpFuture(
        countUpValue: 1,
        maxValue: 100
    );
    yield return future;
    if (future.Error != null)
    {
        if (future.Error is Gs2.Gs2Limit.Exception.OverflowException)
        {
            // The maximum number of times limit has been reached.
        }
        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->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Counter(
        "daily", // limitName
        "counter1" // counterName
    );
    const auto Future = Domain->CountUp(
        1, // countUpValue
        100 // maxValue
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        auto e = Future->GetTask().Error();
        if (e->IsChildOf(Gs2::Limit::Error::FOverflowError::Class))
        {
            // The maximum number of times limit has been reached.
        }
        return false;
    }

    // obtain changed values / result values
    const auto Future2 = Future->GetTask().Result()->Model();
    Future2->StartSynchronousTask();
    if (Future2->GetTask().IsError())
    {
        return Future2->GetTask().Error();
    }
    const auto Result = Future2->GetTask().Result();

getCounter

Get a specific usage limit counter

Retrieves a specific counter by specifying the limit model name and counter name. The counter shows how many times the player has performed this specific action in the current period. Use this to check the remaining attempts for a specific action — for example, displaying “Daily Dungeon: 3/5 attempts used — 2 remaining” on a dungeon entry screen.

Request

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
limitNamestring
~ 128 charsUsage Limit Model Name
The name of the limit model that this counter belongs to. Determines the reset schedule (daily, weekly, monthly, etc.) applied to this counter’s value.
counterNamestring
~ 128 charsCounter Name
A unique identifier for this counter within the limit model. Multiple counters can share the same limit model with different names, allowing separate usage tracking (e.g., one counter per quest or per product) without creating separate limit models.
gameSessionGameSession
GameSession

Result

TypeDescription
itemEzCounterCounter

Implementation Example

    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Counter(
        limitName: "daily",
        counterName: "counter1"
    );
    var item = await domain.ModelAsync();
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Counter(
        limitName: "daily",
        counterName: "counter1"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Counter(
        "daily", // limitName
        "counter1" // counterName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
Value change event handling
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Counter(
        limitName: "daily",
        counterName: "counter1"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Counter(
        limitName: "daily",
        counterName: "counter1"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Counter(
        "daily", // limitName
        "counter1" // counterName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Limit::Model::FCounter> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    Domain->Unsubscribe(CallbackId);

listCounters

Get a list of the player’s usage limit counters

Retrieves all usage limit counters for the player, showing how many times they have performed each limited action. You can optionally filter by limit model name — if omitted, counters for all limit types are returned. Each counter tracks the current count for a specific action (e.g., “Daily Shop Purchase: 2/3 used today”). Use this to build a “Remaining Attempts” or “Daily Limits” overview screen — for example, showing “Shop purchases: 2/3, Dungeon entries: 1/5, Free gacha: 0/1”.

Request

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
limitNamestring~ 128 charsUsage Limit Model name
Usage Limit Model-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSessionGameSession
GameSession
pageTokenstring~ 1024 charsToken specifying the position from which to start acquiring data
limitint301 ~ 1000Number of data items to retrieve

Result

TypeDescription
itemsList<EzCounter>List of Counter
nextPageTokenstringPage token to retrieve the rest of the listing

Implementation Example

    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var items = await domain.CountersAsync(
        limitName: "daily"
    ).ToListAsync();
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    var it = domain.Counters(
        limitName: "daily"
    );
    List<EzCounter> items = new List<EzCounter>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    const auto It = Domain->Counters(
        "daily" // limitName
    );
    TArray<Gs2::UE5::Limit::Model::FEzCounterPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
Value change event handling
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // Start event handling
    var callbackId = domain.SubscribeCounters(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeCounters(callbackId);
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // Start event handling
    var callbackId = domain.SubscribeCounters(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeCounters(callbackId);
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // Start event handling
    const auto CallbackId = Domain->SubscribeCounters(
        []() {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    Domain->UnsubscribeCounters(CallbackId);

getLimitModel

Get a specific usage limit definition by name

Retrieves a single usage limit model by specifying its name. The returned information includes the reset type (not reset / daily / weekly / monthly) and related settings. Use this to display the rules of a specific limit — for example, showing “Daily Shop Limit — Resets every day at midnight” on a shop detail screen.

Request

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
limitNamestring
~ 128 charsUsage Limit Model name
Usage Limit Model-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).

Result

TypeDescription
itemEzLimitModelUsage Limit Model

Implementation Example

    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).LimitModel(
        limitName: "limit-model-0001"
    );
    var item = await domain.ModelAsync();
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).LimitModel(
        limitName: "limit-model-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->LimitModel(
        "limit-model-0001" // limitName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
Value change event handling
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).LimitModel(
        limitName: "limit-model-0001"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    ).LimitModel(
        limitName: "limit-model-0001"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    )->LimitModel(
        "limit-model-0001" // limitName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::Limit::Model::FLimitModel> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    Domain->Unsubscribe(CallbackId);

listLimitModels

Get a list of usage limit definitions

Retrieves all usage limit models registered in this namespace. A limit model defines how a usage counter works — most importantly, when it resets. Reset options include:

  • Not reset: counter never resets (e.g., one-time first-clear bonus)
  • Daily: resets every day (e.g., “buy up to 3 times per day”)
  • Weekly: resets every week (e.g., weekly dungeon attempts)
  • Monthly: resets every month (e.g., monthly reward claims) Use this to see what types of usage limits exist in the game — for example, to display “Daily Limits”, “Weekly Limits” categories in a shop or activity screen.

Request

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).

Result

TypeDescription
itemsList<EzLimitModel>List of Usage Limit Models

Implementation Example

    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.LimitModelsAsync(
    ).ToListAsync();
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.LimitModels(
    );
    List<EzLimitModel> items = new List<EzLimitModel>();
    while (it.HasNext())
    {
        yield return it.Next();
        if (it.Error != null)
        {
            onError.Invoke(it.Error, null);
            break;
        }
        if (it.Current != null)
        {
            items.Add(it.Current);
        }
        else
        {
            break;
        }
    }
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->LimitModels(
    );
    TArray<Gs2::UE5::Limit::Model::FEzLimitModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
Value change event handling
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeLimitModels(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeLimitModels(callbackId);
    var domain = gs2.Limit.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeLimitModels(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeLimitModels(callbackId);
    const auto Domain = Gs2->Limit->Namespace(
        "namespace-0001" // namespaceName
    );
    
    // Start event handling
    const auto CallbackId = Domain->SubscribeLimitModels(
        []() {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    Domain->UnsubscribeLimitModels(CallbackId);