GS2-Idle
Implements a mechanism that grants rewards based on how long the game has not been played. For smartphone games, a design where “you launch the app after a while and obtain a large amount of rewards” strongly contributes to encouraging players to return. GS2-Idle is a microservice that makes it easy to incorporate such idle rewards.
graph LR Start["Start waiting"] --> Idle["Idle time elapses"] Idle --> Prediction["Retrieve scheduled rewards"] Prediction --> Receive["Receive rewards"] Receive --> Start
Categories
Multiple idle rewards can be provided. Players can have one waiting time per category.
Categories can be used as independent idle-reward units, such as “automatic recovery of a character’s stamina”, “automatic mining at a mining site”, or “automatic generation of materials”.
Idle time
For each category, you can set how many minutes of idle time grants a reward and the initial value of the maximum idle time.
The maximum idle time can be raised per player. Whether to reset unused idle time after receiving rewards or carry it over to the next time can be selected via rewardResetMode.
rewardResetMode | Behavior |
|---|---|
Reset | When the reward is received, the elapsed time is reset to 0. Any remainder time before the next reward timing is discarded. |
CarryOver | When the reward is received, only the already-acquired interval is subtracted from the elapsed time. The remainder time is carried over to the next wait. |
Idle Reward
Define the list of items obtainable after a set idle time has elapsed for idle rewards. Multiple rewards (up to 10) can be set up, such as “experience + items”.
In addition, multiple reward lists can be set so that the reward contents can have variations within the waiting time.
For example, you can obtain “Experience +10” and “Enhancement Material Lv.1 x 1” for every 10 minutes of waiting. However, at every 60-minute timing, instead of the above rewards, you obtain “Experience +20” and “Enhancement Material Lv.2 x 1”. Let’s consider an example like the above.
In this case, you set up a table like the following for the idle rewards.
| - | reward1 | reward2 |
|---|---|---|
| 1 | Experience +10 | Enhancement Material Lv.1 x 1 |
| 2 | Experience +10 | Enhancement Material Lv.1 x 1 |
| 3 | Experience +10 | Enhancement Material Lv.1 x 1 |
| 4 | Experience +10 | Enhancement Material Lv.1 x 1 |
| 5 | Experience +10 | Enhancement Material Lv.1 x 1 |
| 6 | Experience +20 | Enhancement Material Lv.2 x 1 |
This allows you to change the reward item contents according to the elapsed time. The reward contents loop, so after 2 hours, you will obtain the items “1,2,3,4,5,6,1,2,3,4,5,6”.
Random drawings for idle rewards
Sometimes you want more randomness in the reward contents. In such cases, set up GS2-Lottery’s lottery process for the rewards.
In conventional GS2-Lottery, the result is not determined until the lottery is drawn. However, when using GS2-Idle, a random-number seed is generated at the start of the waiting period. By using this seed for the lottery when calculating rewards, the randomly drawn item contents can be presented to the player even during the waiting period, and the contents remain unchanged. (Changing the GS2-Lottery prize table will break this premise.)
Scheduling of waiting time
Each category can be associated with a GS2-Schedule event so that idle rewards linked to the event can be implemented.
Suppose the event duration is 2023-01-01 00:00 to 2023-02-01 00:00, and the wait begins at 2023-01-31 23:00. In this case, the idle-time count stops at the moment 2023-02-01 00:00 is reached.
Therefore, the content will be the same whether you receive the reward at 2023-02-01 01:00 or at 2023-02-01 09:00.
If the event has a recurring setting, the idle time is reset when the recurrence count changes. For example, in a recurring event from every Monday 00:00 to Tuesday 00:00, the waiting time is reset at the moment it reaches 00:00 the following Monday, even if you have not received the previous week’s reward.
Apart from the waiting-time schedule, you can set a period during which rewards can be received. Outside the receivable period you can still use Prediction to obtain the scheduled reward, but calling the receive API will result in an error.
Status
Each player holds one Status per category.
The Status contains the following information:
| Field | Description |
|---|---|
idleStartedAt | The time at which waiting started |
idleMinutes | The accumulated idle time (in minutes) |
nextRewardsAt | The next reward acquisition timing |
maximumIdleMinutes | The upper limit of idle time applied to this player |
randomSeed | A fixed seed for lotteries combined with GS2-Lottery |
Example implementation
Start of waiting
Waiting is started when the waiting-time information is retrieved for the first time.
var item = await gs2.Idle.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
category: "category-0001"
).ModelAsync(); const auto Future = Gs2->Idle->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Status(
"category-0001" // categoryName
)->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;Retrieve the list of statuses (idle information)
var items = await gs2.Idle.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).StatusesAsync(
).ToListAsync(); const auto It = Gs2->Idle->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Statuses(
);
TArray<Gs2::UE5::Idle::Model::FEzStatusPtr> Result;
for (auto Item : *It)
{
if (Item.IsError())
{
return false;
}
Result.Add(Item.Current());
}Check the reward contents
Use the Prediction API to check the scheduled rewards before receiving them.
This can be used in cases where you want to present in advance to the player something like “if you wait N more minutes, you can obtain these items”.
var items = await gs2.Idle.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
category: "category-0001"
).PredictionAsync(); const auto Domain = Gs2->Idle->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Status(
"category-0001" // categoryName
);
const auto Future = Domain->Prediction(
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}
// obtain changed values / result values
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError()) return false;
const auto Result = Future2->GetTask().Result();Receiving rewards
When a reward is received, the waiting time is reset.
Also, any remaining idle time before the next reward timing is reset to 0 (when rewardResetMode is CarryOver, the remainder time is carried over to the next time).
await gs2.Idle.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
category: "category-0001"
).ReceiveAsync(); const auto Future = Gs2->Idle->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Status(
"category-0001" // categoryName
)->Receive();
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;Script Triggers
Setting overrideAcquireActionsScriptId or receiveScript in the namespace allows custom scripts to be executed before and after reward calculation and reward-receiving processes.
Triggers support both synchronous and asynchronous execution. Asynchronous processing also supports external integration through GS2-Script or Amazon EventBridge.
The main event triggers and script setting names that can be configured are as follows:
overrideAcquireActionsScriptId: A synchronous script executed during reward calculation. It allows you to dynamically override the reward list. It can be used to swap rewards according to the player’s state.receiveScript(completion notification:receiveDone): before and after reward receiving. Synchronous execution allows for permitting/denying the receipt or applying multiplier corrections, while asynchronous execution enables external integration via Amazon EventBridge.
Transaction Actions
GS2-Idle provides the following transaction actions:
| Type | Action | Description |
|---|---|---|
| Consume | Gs2Idle:DecreaseMaximumIdleMinutesByUserId | Subtract from the maximum idle time |
| Acquire | Gs2Idle:IncreaseMaximumIdleMinutesByUserId | Add to the maximum idle time |
| Acquire | Gs2Idle:SetMaximumIdleMinutesByUserId | Set the maximum idle time |
| Acquire | Gs2Idle:ReceiveByUserId | Receive rewards |
By using “Add maximum idle time” as an acquire action, it is possible to perform processes such as automatically expanding the upper limit of accumulable idle rewards when a specific item is obtained or when a player’s rank increases. This allows players to accumulate more idle rewards as they grow, contributing to an improved play experience.
Adjustment with buffs
By using GS2-Buff, you can correct the category model’s acquireActions or the per-player maximumIdleMinutes with buffs, dynamically adjusting the contents of idle rewards and the maximum idle time according to events and campaigns.
For example, you can run operations such as “idle rewards are 1.5x on weekends” or “players holding a specific title get +60 minutes of maximum idle time”.
Managing master data
By registering master data, you can configure the data and behavior available to the microservice.
The types of master data are as follows:
CategoryModel: settings for idle time and reward tables
Below is an example JSON of master data.
{
"version": "2024-04-25",
"categoryModels": [
{
"name": "category-0001",
"metadata": "Stamina",
"rewardIntervalMinutes": 10,
"defaultMaximumIdleMinutes": 360,
"rewardResetMode": "CarryOver",
"acquireActions": [
{
"acquireActions": [
{
"action": "Gs2Experience:AddExperienceByUserId",
"request": "{\"experienceValue\": 10}"
}
]
}
]
}
]
}Master data can be registered from the Management Console, or you can set up a workflow that reflects data from GitHub or registers via CI using GS2-Deploy.