GS2-Mission
A mechanism for rewarding players based on actions they have accumulated in the game. It is used to implement features generally referred to as achievements, trophies, and missions.
graph TD Action["In-game action<br/>(quest clear / gacha draw, etc.)"] -- "Increase counter<br/>(IncreaseCounterByUserId)" --> Counter["Mission counter<br/>(Counter / Scope)"] Counter -- "Target value reached" --> Task["Mission task<br/>(MissionTaskModel)"] Task -- "ReceiveRewards" --> Reward["completeAcquireActions"] Reward --> Distributor["GS2-Distributor<br/>reward distribution"] Task --> Group["Mission group<br/>(MissionGroupModel)"] Group -- "Reset receipt flag<br/>based on resetType" --> Task
Mission Counter
An entity for counting the number of times based on a player’s actions. Counters are provided to count in-game action counts such as the number of times a quest has been cleared, the number of times a character has been enhanced, or the number of times a gacha has been drawn.
A counter can have scopes. The following values can be set for a scope.
| Scope Type | Scope Content |
|---|---|
| Not reset | Cumulative total since gameplay started |
| Reset at X o’clock daily | Number of times executed today |
| Reset at X o’clock on day-of-week X weekly | Number of times executed this week |
| Reset at X o’clock on day X of every month | Number of times executed this month |
| Reset every fixed number of days | Reset every specified number of days from a base time |
| Count up only when a verify action matches | Increment counter based on the result of a verifyAction |
Counter values are managed per scope, and the value of each scope can be used as a mission achievement condition.
graph LR Up["Increase counter request"] --> Counter["Counter"] Counter --> Scope1["Scope 1<br/>Not reset"] Counter --> Scope2["Scope 2<br/>Reset daily"] Counter --> Scope3["Scope 3<br/>Reset weekly"] Scope1 -- ScopedValue --> Mission1["Cumulative 100 times mission"] Scope2 -- ScopedValue --> Mission2["Daily 10 times mission"] Scope3 -- ScopedValue --> Mission3["Weekly 50 times mission"]
Scope Control with Verify Actions
By using scopeType=verifyAction, you can define arbitrary conditions with conditionName and condition,
and control whether to increment the counter based on the verification result of another microservice.
This makes it possible to create scopes that only increment during a specific event period, or that only increment when a specific character is in the formation.
Challenge Period
CounterModel can be configured with challengePeriodEventId, where specifying a GS2-Schedule event GRN limits the period during which the counter can be operated.
Counters cannot be updated outside the specified period, which is useful for limited-time events.
Mission Task
This is master data that defines the goals presented to the player.
It defines a “mission counter”, a “scope”, a “target value”, and a “reward” obtained when the target is met. For example, the following settings can be configured.
| Mission Counter | Scope Type | Target Value | Reward |
|---|---|---|---|
| Number of quest clears | Reset at X o’clock daily | 10 | Item A |
| Number of quest clears | Reset at X o’clock on day-of-week X weekly | 50 | Item B |
| Number of character enhancements | Reset at X o’clock daily | 5 | Item C |
Task Dependencies
By specifying premiseMissionTaskName, you can define missions that can only be received after completing a preceding task.
You can build a stepwise achievement flow such as “completing task A makes task B receivable”.
Achievement Decisions Using Verify Actions
By specifying verifyActions for verifyCompleteType, achievement of a task can be decided by whether verify actions from other microservices are satisfied.
When this feature is used, the achievement decision via the Complete object provided by GS2-Mission (server-side automatic decision) is not performed. Therefore, the achievement state must be computed on the client to control the receipt UI, and the reward receipt action must be explicitly executed.
To re-evaluate achievability on the server side, you can call the EvaluateComplete API to refresh the Complete state.
Challenge Period
MissionTaskModel’s challengePeriodEventId lets you limit the achievable period using a GS2-Schedule event.
Achieved tasks can still be received after the period ends, but if a reset interval is configured on the mission task, they become unreceivable when the reset timing arrives.
Mission Group
An entity that bundles multiple mission tasks. A mission group can have a reset cycle for the reward receipt flag.
| Mission Counter | Scope Type | Target Value | Reward |
|---|---|---|---|
| Number of quest clears | Reset at X o’clock daily | 10 | Item A |
| Number of character enhancements | Reset at X o’clock daily | 5 | Item C |
By associating these mission tasks with a single mission group and configuring the mission group’s reward receipt flag reset cycle to “Reset at X o’clock daily” as well, players can receive rewards every day as long as they complete the mission tasks daily.
Reset Type
resetType can be one of the following.
resetType |
Description |
|---|---|
notReset |
Do not reset (for achievement/trophy-like usage) |
daily |
Reset daily at resetHour |
weekly |
Reset weekly on resetDayOfWeek at resetHour |
monthly |
Reset monthly on resetDayOfMonth at resetHour |
days |
Reset every days days starting from anchorTimestamp |
Resetting Every Arbitrary Number of Days
By specifying days for resetType, you can reset the reward receipt flag every specified number of days from the base time specified in anchorTimestamp.
For example, you can run an operation that resets every 3 days from the start of an event.
Script Triggers
By configuring missionCompleteScript, counterIncrementScript, and receiveRewardsScript on the namespace, you can invoke custom scripts at the timing of mission completion, counter increment, and reward receipt.
The main event triggers and the script setting names that can be configured are as follows.
missionCompleteScript: Mission completioncounterIncrementScript: Counter incrementreceiveRewardsScript: Reward receipt
By leveraging these, you can customize BI integration on completion, detection of illegitimate counter operations, and special processing on reward receipt.
Push Notifications
The main push notifications and their setting names are as follows.
completeNotification: Notifies when a mission task is completed
Mobile push forwarding to offline devices is also supported, encouraging players to receive their rewards.
Master Data Management
By registering master data, you can configure the data and behaviors available in the microservice.
The types of master data are as follows.
CounterModel: A list ofCounterScopeModeldefining counting targets and reset cyclesMissionGroupModel: Group-level reset settings and the tasks belonging to itMissionTaskModel: Achievement conditions (counter and target value) and the reward for achievement
In addition to registering master data from the management console, you can also reflect data from GitHub or build a workflow that registers it from CI using GS2-Deploy.
The following is an example of master data in JSON.
{
"version": "2019-04-12",
"counters": [
{
"name": "quest_complete",
"metadata": "Quest clear count",
"scopes": [
{
"scopeType": "resetTimingScope",
"resetType": "daily",
"resetHour": 5
},
{
"scopeType": "resetTimingScope",
"resetType": "weekly",
"resetDayOfWeek": "monday",
"resetHour": 5
}
]
}
],
"missionGroups": [
{
"name": "daily-mission",
"metadata": "Daily mission",
"resetType": "daily",
"resetHour": 5,
"tasks": [
{
"name": "mission-task-0001",
"metadata": "Clear 10 quests",
"counterName": "quest_complete",
"targetResetType": "daily",
"targetValue": 10,
"completeAcquireActions": []
}
]
}
]
}GS2-Buff Integration
By integrating with GS2-Buff, you can apply buffs to the completeAcquireActions of mission task models to flexibly adjust reward amounts according to events and other factors.
Transaction Actions
GS2-Mission provides the following transaction actions.
- Verify action: Verify mission achievement status, verify counter value
- Consume action: Receive rewards (including batch), decrement or reset a counter
- Acquire action: Increment or set a counter, restore reward receipt state (mark as unreceived)
By using “Increment counter” as an acquire action, you can directly advance mission progress as a reward for purchasing an item at a shop or clearing a quest. Also, by using “Decrement counter” as a consume action, you can safely operate within a transaction to consume a mission counter as a cost for a specific benefit (for example, a point-consumption mission).
Implementation Examples
Incrementing a Mission Counter
Incrementing a mission counter cannot be performed with game engine SDKs.
Please implement it by, for example, incrementing a counter as a GS2-Quest clear reward or a GS2-Lottery prize. If you want to increment a counter directly from the client, the server should issue a transaction and run it as an acquire action via GS2-Distributor.
Retrieving Mission Task Achievement Status and Reward Receipt Status
var item = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Complete(
missionGroupName: "mission-group-0001"
).ModelAsync(); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Complete(
"mission-group-0001" // missionGroupName
);
const auto Future = Domain->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;
const auto Result = Future->GetTask().Result();Receiving Mission Completion Rewards
var result = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Complete(
missionGroupName: "mission-group-0001"
).ReceiveRewardsAsync(
missionTaskName: "mission-task-0001"
);
await result.WaitAsync(); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Complete(
"mission-group-0001" // missionGroupName
);
const auto Future = Domain->ReceiveRewards(
"mission-task-0001"
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;
const auto Transaction = Future->GetTask().Result();
const auto Future2 = Transaction->Wait();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError()) return false;Batch Receipt of Completed Rewards
When you want to receive all completed but unclaimed tasks at once, you can use BatchReceiveRewards.
By specifying multiple missionTaskName values, the rewards are received as a single transaction.
var result = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Complete(
missionGroupName: "mission-group-0001"
).BatchReceiveRewardsAsync(
missionTaskNames: new [] {
"mission-task-0001",
"mission-task-0002",
}
);
await result.WaitAsync(); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Complete(
"mission-group-0001" // missionGroupName
);
const auto Future = Domain->BatchReceiveRewards(
[]
{
auto v = MakeShared<TArray<FString>>();
v->Add("mission-task-0001");
v->Add("mission-task-0002");
return v;
}()
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;Re-evaluating Task Achievement Using Verify Actions
Call this when you want to re-evaluate on the server the achievement status of tasks for which verifyCompleteType is set to verifyActions.
var result = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Complete(
missionGroupName: "mission-group-0001"
).EvaluateCompleteAsync(
); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Complete(
"mission-group-0001" // missionGroupName
);
const auto Future = Domain->EvaluateComplete();
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;Retrieving the Mission Counter Value
var item = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Counter(
counterName: "quest_complete"
).ModelAsync(); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Counter(
"quest_complete" // counterName
);
const auto Future = Domain->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;
const auto Result = Future->GetTask().Result();Resetting a Mission Counter
You can manually reset the counter value for a specific scope. This can be used to initialize event-related counters at the end of an event.
var result = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Counter(
counterName: "quest_complete"
).ResetCounterAsync(
scopes: new [] {
new Gs2.Unity.Gs2Mission.Model.EzScopedValue() {
ResetType = "daily",
Value = 0,
},
}
); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->Me(
AccessToken
)->Counter(
"quest_complete" // counterName
);
const auto Future = Domain->ResetCounter(
Scopes
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError()) return false;Retrieving the Mission Target Values
var items = await gs2.Mission.Namespace(
namespaceName: "namespace-0001"
).MissionGroupModel(
missionGroupName: "mission-group-0001"
).MissionTaskModelsAsync(
).ToListAsync(); const auto Domain = Gs2->Mission->Namespace(
"namespace-0001" // namespaceName
)->MissionGroupModel(
"mission-group-0001" // missionGroupName
);
const auto It = Domain->MissionTaskModels(
);
TArray<Gs2::UE5::Mission::Model::FEzMissionTaskModelPtr> Result;
for (auto Item : *It)
{
if (Item.IsError())
{
return false;
}
Result.Add(Item.Current());
}