GS2-Exchange Deploy/CDK Reference
Entities
Resources targeted by the Deploy operation
Namespace
Namespace
A Namespace allows multiple independent instances of the same service within a single project by separating data spaces and usage contexts. Each GS2 service is managed on a per-namespace basis. Even when using the same service, if the namespace differs, the data is treated as a completely independent data space.
Therefore, you must create a namespace before you can start using each service.
Request
Resource creation and update requests
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| name | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||
| description | string | ~ 1024 chars | Description | |||
| enableAwaitExchange | bool | false | Whether to enable exchanges that require a waiting time before receiving results When enabled, exchange rate models with await timing type can be used. These exchanges require real-time to elapse before rewards can be claimed, enabling crafting or production mechanics where players must wait for the result. | |||
| enableDirectExchange | bool | true | Allow direct exchange API calls When enabled, clients can call the exchange API directly to perform resource exchanges. When disabled, exchanges can only be triggered via transaction actions (transactions), providing tighter server-side control over when exchanges occur. | |||
| transactionSetting | TransactionSetting | ✓ | Transaction Setting Configuration for controlling how distributed transactions are executed when processing exchange operations. Supports auto-run, atomic commit, and async processing options. | |||
| exchangeScript | ScriptSetting | Script to run when an attempt is made to perform an exchange Script Trigger Reference - exchange | ||||
| incrementalExchangeScript | ScriptSetting | Script to run when an attempt is made to perform an incremental exchange Script Trigger Reference - incrementalExchange | ||||
| acquireAwaitScript | ScriptSetting | Script setting executed when the waiting period completes and the reward is about to be acquired in an await-type exchange Script Trigger Reference - acquireAwait | ||||
| logSetting | LogSetting | Log Output Setting Configuration for outputting log data of exchange operations to GS2-Log. By specifying a GS2-Log namespace, API request and response logs for exchange, incremental exchange, and await operations can be collected. |
GetAttr
Resource creation results that can be retrieved using the !GetAttr tag
| Type | Description | |
|---|---|---|
| Item | Namespace | Namespace created |
Implementation Example
Type: GS2::Exchange::Namespace
Properties:
Name: namespace-0001
Description: null
EnableAwaitExchange: null
EnableDirectExchange: null
TransactionSetting:
EnableAutoRun: true
QueueNamespaceId: grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001
ExchangeScript: null
IncrementalExchangeScript: null
AcquireAwaitScript: null
LogSetting:
LoggingNamespaceId: grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001import (
"github.com/gs2io/gs2-golang-cdk/core"
"github.com/gs2io/gs2-golang-cdk/exchange"
"github.com/openlyinc/pointy"
)
SampleStack := core.NewStack()
exchange.NewNamespace(
&SampleStack,
"namespace-0001",
exchange.NamespaceOptions{
TransactionSetting: core.NewTransactionSetting(
core.TransactionSettingOptions{
QueueNamespaceId: pointy.String("grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"),
},
),
LogSetting: &core.LogSetting{
LoggingNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001",
},
},
)
println(SampleStack.Yaml()) // Generate Templateclass SampleStack extends \Gs2Cdk\Core\Model\Stack
{
function __construct() {
parent::__construct();
new \Gs2Cdk\Exchange\Model\Namespace_(
stack: $this,
name: "namespace-0001",
options: new \Gs2Cdk\Exchange\Model\Options\NamespaceOptions(
transactionSetting: new \Gs2Cdk\Core\Model\TransactionSetting(
new \Gs2Cdk\Core\Model\TransactionSettingOptions(
queueNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"
)
),
logSetting: new \Gs2Cdk\Core\Model\LogSetting(
loggingNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
)
)
);
}
}
print((new SampleStack())->yaml()); // Generate Templateclass SampleStack extends io.gs2.cdk.core.model.Stack
{
public SampleStack() {
super();
new io.gs2.cdk.exchange.model.Namespace(
this,
"namespace-0001",
new io.gs2.cdk.exchange.model.options.NamespaceOptions()
.withTransactionSetting(new io.gs2.cdk.core.model.TransactionSetting(
new io.gs2.cdk.core.model.options.TransactionSettingOptions()
.withQueueNamespaceId("grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001")
))
.withLogSetting(new io.gs2.cdk.core.model.LogSetting(
"grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
))
);
}
}
System.out.println(new SampleStack().yaml()); // Generate Templatepublic class SampleStack : Gs2Cdk.Core.Model.Stack
{
public SampleStack() {
new Gs2Cdk.Gs2Exchange.Model.Namespace(
stack: this,
name: "namespace-0001",
options: new Gs2Cdk.Gs2Exchange.Model.Options.NamespaceOptions
{
transactionSetting = new Gs2Cdk.Core.Model.TransactionSetting(
options: new Gs2Cdk.Core.Model.TransactionSettingOptions
{
queueNamespaceId = "grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"
}
),
logSetting = new Gs2Cdk.Core.Model.LogSetting(
loggingNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
)
}
);
}
}
Debug.Log(new SampleStack().Yaml()); // Generate Templateimport core from "@/gs2cdk/core";
import exchange from "@/gs2cdk/exchange";
class SampleStack extends core.Stack
{
public constructor() {
super();
new exchange.model.Namespace(
this,
"namespace-0001",
{
transactionSetting: new core.TransactionSetting(
{
queueNamespaceId: "grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001"
}
),
logSetting: new core.LogSetting(
"grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001"
)
}
);
}
}
console.log(new SampleStack().yaml()); // Generate Templatefrom gs2_cdk import Stack, core, exchange
class SampleStack(Stack):
def __init__(self):
super().__init__()
exchange.Namespace(
stack=self,
name='namespace-0001',
options=exchange.NamespaceOptions(
transaction_setting=core.TransactionSetting(
options=core.TransactionSettingOptions(
queue_namespace_id='grn:gs2:ap-northeast-1:YourOwnerId:queue:queue-0001',
)
),
log_setting=core.LogSetting(
logging_namespace_id='grn:gs2:ap-northeast-1:YourOwnerId:log:namespace-0001',
),
),
)
print(SampleStack().yaml()) # Generate TemplateTransactionSetting
Transaction Setting
Transaction Setting controls how transactions are executed, including their consistency, asynchronous processing, and conflict avoidance mechanisms. Combining features like AutoRun, AtomicCommit, asynchronous execution using GS2-Distributor, batch application of script results, and asynchronous Acquire Actions via GS2-JobQueue enables robust transaction management tailored to game logic.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| enableAutoRun | bool | false | Whether to automatically execute issued transactions on the server side | |||
| enableAtomicCommit | bool | {enableAutoRun} == true | false | Whether to commit the execution of transactions atomically * Applicable only if enableAutoRun is true | ||
| transactionUseDistributor | bool | {enableAtomicCommit} == true | false | Whether to execute transactions asynchronously * Applicable only if enableAtomicCommit is true | ||
| commitScriptResultInUseDistributor | bool | {transactionUseDistributor} == true | false | Whether to execute the commit processing of the script result asynchronously * Applicable only if transactionUseDistributor is true | ||
| acquireActionUseJobQueue | bool | {enableAtomicCommit} == true | false | Whether to use GS2-JobQueue to execute the acquire action * Applicable only if enableAtomicCommit is true | ||
| distributorNamespaceId | string | “grn:gs2:{region}:{ownerId}:distributor:default” | ~ 1024 chars | GS2-Distributor Namespace GRN used to execute transactions | ||
| queueNamespaceId | string | “grn:gs2:{region}:{ownerId}:queue:default” | ~ 1024 chars | GS2-JobQueue Namespace GRN used to execute transactions |
ScriptSetting
Script Setting
In GS2, you can associate custom scripts with microservice events and execute them. This model holds the settings for triggering script execution.
There are two main ways to execute a script: synchronous execution and asynchronous execution. Synchronous execution blocks processing until the script has finished executing. Instead, you can use the script’s execution results to halt API execution or control the API’s response content.
In contrast, asynchronous execution does not block processing until the script has finished executing. However, because the script result cannot be used to stop the API execution or modify the API response, asynchronous execution does not affect the API response flow and is generally recommended.
There are two types of asynchronous execution methods: GS2-Script and Amazon EventBridge. By using Amazon EventBridge, you can write processing in languages other than Lua.
| Type | Condition | Required | Default | Value Limits | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| triggerScriptId | string | ~ 1024 chars | GS2-Script script GRN
executed synchronously when the API is executed Must be specified in GRN format starting with “grn:gs2:”. | |||||||||||
| doneTriggerTargetType | String Enum enum { “none”, “gs2_script”, “aws” } | “none” | How to execute asynchronous scripts Specifies the type of script to use for asynchronous execution. You can choose from “Do not use asynchronous execution (none)”, “Use GS2-Script (gs2_script)”, and “Use Amazon EventBridge (aws)”.
| |||||||||||
| doneTriggerScriptId | string | {doneTriggerTargetType} == “gs2_script” | ~ 1024 chars | GS2-Script script GRN
for asynchronous execution Must be specified in GRN format starting with “grn:gs2:”. * Applicable only if doneTriggerTargetType is “gs2_script” | ||||||||||
| doneTriggerQueueNamespaceId | string | {doneTriggerTargetType} == “gs2_script” | ~ 1024 chars | GS2-JobQueue namespace GRN
to execute asynchronous execution scripts If you want to execute asynchronous execution scripts via GS2-JobQueue instead of executing them directly, specify the GS2-JobQueue namespace GRN. There are not many cases where GS2-JobQueue is required, so you generally do not need to specify it unless you have a specific reason. * Applicable only if doneTriggerTargetType is “gs2_script” |
LogSetting
Log Output Setting
Log Output Setting defines how log data is exported. This type holds the GS2-Log namespace identifier (Namespace ID) used to export log data. Specify the GS2-Log namespace where log data is collected and stored in the GRN format for the Log Namespace ID (loggingNamespaceId). Configuring this setting ensures that log data for API requests and responses occurring within the specified namespace is output to the target GS2-Log namespace. GS2-Log provides real-time logs that can be used for system monitoring, analysis, debugging, and other operational purposes.
| Type | Condition | Required | Default | Value Limits | Description | |
|---|---|---|---|---|---|---|
| loggingNamespaceId | string | ✓ | ~ 1024 chars | GS2-Log namespace GRN
to output logs Must be specified in GRN format starting with “grn:gs2:”. |
CurrentRateMaster
Currently active Rate Model master data
This master data describes the definitions of Rate Models currently active within the namespace. GS2 uses JSON format files for managing master data. By uploading these files, the master data settings are updated on the server.
To create JSON files, GS2 provides a master data editor within the management console. Additionally, you can create tools better suited for game operations and export JSON files in the appropriate format.
Note
Please refer to Master Data Reference of GS2-Exchange for the JSON file format.Request
Resource creation and update requests
| Type | Condition | Required | Default | Value Limits | Description | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128 chars | Namespace name Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||||||||
| mode | String Enum enum { “direct”, “preUpload” } | “direct” | Update mode
| |||||||||
| settings | string | {mode} == “direct” | ✓* | ~ 5242880 chars | Master Data * Required if mode is “direct” | |||||||
| uploadToken | string | {mode} == “preUpload” | ✓* | ~ 1024 chars | Token obtained by pre-upload Used to apply the uploaded master data. * Required if mode is “preUpload” |
GetAttr
Resource creation results that can be retrieved using the !GetAttr tag
| Type | Description | |
|---|---|---|
| Item | CurrentRateMaster | Updated master data of the currently active Rate Models |
Implementation Example
Type: GS2::Exchange::CurrentRateMaster
Properties:
NamespaceName: namespace-0001
Mode: direct
Settings: {
"version": "2019-08-19",
"rateModels": [
{
"name": "material_n_to_r",
"timingType": "await",
"metadata": "N2R",
"consumeActions": [
{
"action": "Gs2Inventory:ConsumeItemSetByUserId",
"request": {
"namespaceName": "namespace-0001",
"inventoryName": "inventory-0001",
"itemName": "item-0001",
"consumeCount": 1,
"itemSetName": "#{itemSetName}",
"userId": "#{userId}"
}
}
],
"lockTime": 50,
"acquireActions": [
{
"action": "Gs2Inventory:AcquireItemSetByUserId",
"request": {
"namespaceName": "namespace-0001",
"inventoryName": "inventory-0001",
"itemName": "item-0001",
"acquireCount": 1,
"expiresAt": 0,
"createNewItemSet": false,
"itemSetName": "",
"userId": "#{userId}"
}
}
]
},
{
"name": "material_r_to_n",
"timingType": "await",
"metadata": "N2R",
"consumeActions": [
{
"action": "Gs2Inventory:ConsumeItemSetByUserId",
"request": {
"namespaceName": "namespace-0001",
"inventoryName": "inventory-0001",
"itemName": "item-0001",
"consumeCount": 1,
"itemSetName": "#{itemSetName}",
"userId": "#{userId}"
}
}
],
"lockTime": 50,
"acquireActions": [
{
"action": "Gs2Inventory:AcquireItemSetByUserId",
"request": {
"namespaceName": "namespace-0001",
"inventoryName": "inventory-0001",
"itemName": "item-0001",
"acquireCount": 1,
"expiresAt": 0,
"createNewItemSet": false,
"itemSetName": "",
"userId": "#{userId}"
}
}
]
}
],
"incrementalRateModels": []
}
UploadToken: nullimport (
"github.com/gs2io/gs2-golang-cdk/core"
"github.com/gs2io/gs2-golang-cdk/exchange"
"github.com/gs2io/gs2-golang-cdk/inventory"
"github.com/openlyinc/pointy"
)
SampleStack := core.NewStack()
exchange.NewNamespace(
&SampleStack,
"namespace-0001",
exchange.NamespaceOptions{},
).MasterData(
[]exchange.RateModel{
exchange.NewRateModel(
"material_n_to_r",
exchange.RateModelTimingTypeAwait,
exchange.RateModelOptions{
Metadata: pointy.String("N2R"),
ConsumeActions: []core.ConsumeAction{
inventory.ConsumeItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
"#{itemSetName}",
"#{userId}",
),
},
LockTime: pointy.Int32(50),
AcquireActions: []core.AcquireAction{
inventory.AcquireItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
0,
pointy.Bool(false),
"",
"#{userId}",
),
},
},
),
exchange.NewRateModel(
"material_r_to_n",
exchange.RateModelTimingTypeAwait,
exchange.RateModelOptions{
Metadata: pointy.String("N2R"),
ConsumeActions: []core.ConsumeAction{
inventory.ConsumeItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
"#{itemSetName}",
"#{userId}",
),
},
LockTime: pointy.Int32(50),
AcquireActions: []core.AcquireAction{
inventory.AcquireItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
0,
pointy.Bool(false),
"",
"#{userId}",
),
},
},
),
},
[]exchange.IncrementalRateModel{
},
)
println(SampleStack.Yaml()) // Generate Templateclass SampleStack extends \Gs2Cdk\Core\Model\Stack
{
function __construct() {
parent::__construct();
(new \Gs2Cdk\Exchange\Model\Namespace_(
stack: $this,
name: "namespace-0001"
))->masterData(
[
new \Gs2Cdk\Exchange\Model\RateModel(
name:"material_n_to_r",
timingType: \Gs2Cdk\Exchange\Model\Enums\RateModelTimingType::AWAIT,
options: new \Gs2Cdk\Exchange\Model\Options\RateModelOptions(
metadata:"N2R",
consumeActions:[
new \Gs2Cdk\Inventory\StampSheet\ConsumeItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
consumeCount: 1,
itemSetName: "#{itemSetName}",
userId: "#{userId}"
),
],
lockTime:50,
acquireActions:[
new \Gs2Cdk\Inventory\StampSheet\AcquireItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
acquireCount: 1,
expiresAt: 0,
createNewItemSet: false,
itemSetName: "",
userId: "#{userId}"
),
]
)
),
new \Gs2Cdk\Exchange\Model\RateModel(
name:"material_r_to_n",
timingType: \Gs2Cdk\Exchange\Model\Enums\RateModelTimingType::AWAIT,
options: new \Gs2Cdk\Exchange\Model\Options\RateModelOptions(
metadata:"N2R",
consumeActions:[
new \Gs2Cdk\Inventory\StampSheet\ConsumeItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
consumeCount: 1,
itemSetName: "#{itemSetName}",
userId: "#{userId}"
),
],
lockTime:50,
acquireActions:[
new \Gs2Cdk\Inventory\StampSheet\AcquireItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
acquireCount: 1,
expiresAt: 0,
createNewItemSet: false,
itemSetName: "",
userId: "#{userId}"
),
]
)
)
],
[
]
);
}
}
print((new SampleStack())->yaml()); // Generate Templateclass SampleStack extends io.gs2.cdk.core.model.Stack
{
public SampleStack() {
super();
new io.gs2.cdk.exchange.model.Namespace(
this,
"namespace-0001"
).masterData(
Arrays.asList(
new io.gs2.cdk.exchange.model.RateModel(
"material_n_to_r",
io.gs2.cdk.exchange.model.enums.RateModelTimingType.AWAIT,
new io.gs2.cdk.exchange.model.options.RateModelOptions()
.withMetadata("N2R")
.withConsumeActions(Arrays.asList(
new io.gs2.cdk.inventory.stampSheet.ConsumeItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1L,
"#{itemSetName}",
"#{userId}"
)
))
.withLockTime(50)
.withAcquireActions(Arrays.asList(
new io.gs2.cdk.inventory.stampSheet.AcquireItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1L,
0L,
false,
"",
"#{userId}"
)
))
),
new io.gs2.cdk.exchange.model.RateModel(
"material_r_to_n",
io.gs2.cdk.exchange.model.enums.RateModelTimingType.AWAIT,
new io.gs2.cdk.exchange.model.options.RateModelOptions()
.withMetadata("N2R")
.withConsumeActions(Arrays.asList(
new io.gs2.cdk.inventory.stampSheet.ConsumeItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1L,
"#{itemSetName}",
"#{userId}"
)
))
.withLockTime(50)
.withAcquireActions(Arrays.asList(
new io.gs2.cdk.inventory.stampSheet.AcquireItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1L,
0L,
false,
"",
"#{userId}"
)
))
)
),
Arrays.asList(
)
);
}
}
System.out.println(new SampleStack().yaml()); // Generate Templatepublic class SampleStack : Gs2Cdk.Core.Model.Stack
{
public SampleStack() {
new Gs2Cdk.Gs2Exchange.Model.Namespace(
stack: this,
name: "namespace-0001"
).MasterData(
new Gs2Cdk.Gs2Exchange.Model.RateModel[] {
new Gs2Cdk.Gs2Exchange.Model.RateModel(
name: "material_n_to_r",
timingType: Gs2Cdk.Gs2Exchange.Model.Enums.RateModelTimingType.Await,
options: new Gs2Cdk.Gs2Exchange.Model.Options.RateModelOptions
{
metadata = "N2R",
consumeActions = new Gs2Cdk.Core.Model.ConsumeAction[]
{
new Gs2Cdk.Gs2Inventory.StampSheet.ConsumeItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
consumeCount: 1,
itemSetName: "#{itemSetName}",
userId: "#{userId}"
)
},
lockTime = 50,
acquireActions = new Gs2Cdk.Core.Model.AcquireAction[]
{
new Gs2Cdk.Gs2Inventory.StampSheet.AcquireItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
acquireCount: 1,
expiresAt: 0,
createNewItemSet: false,
itemSetName: "",
userId: "#{userId}"
)
}
}
),
new Gs2Cdk.Gs2Exchange.Model.RateModel(
name: "material_r_to_n",
timingType: Gs2Cdk.Gs2Exchange.Model.Enums.RateModelTimingType.Await,
options: new Gs2Cdk.Gs2Exchange.Model.Options.RateModelOptions
{
metadata = "N2R",
consumeActions = new Gs2Cdk.Core.Model.ConsumeAction[]
{
new Gs2Cdk.Gs2Inventory.StampSheet.ConsumeItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
consumeCount: 1,
itemSetName: "#{itemSetName}",
userId: "#{userId}"
)
},
lockTime = 50,
acquireActions = new Gs2Cdk.Core.Model.AcquireAction[]
{
new Gs2Cdk.Gs2Inventory.StampSheet.AcquireItemSetByUserId(
namespaceName: "namespace-0001",
inventoryName: "inventory-0001",
itemName: "item-0001",
acquireCount: 1,
expiresAt: 0,
createNewItemSet: false,
itemSetName: "",
userId: "#{userId}"
)
}
}
)
},
new Gs2Cdk.Gs2Exchange.Model.IncrementalRateModel[] {
}
);
}
}
Debug.Log(new SampleStack().Yaml()); // Generate Templateimport core from "@/gs2cdk/core";
import exchange from "@/gs2cdk/exchange";
import inventory from "@/gs2cdk/inventory";
class SampleStack extends core.Stack
{
public constructor() {
super();
new exchange.model.Namespace(
this,
"namespace-0001",
).masterData(
[
new exchange.model.RateModel(
"material_n_to_r",
exchange.model.RateModelTimingType.AWAIT,
{
metadata: "N2R",
consumeActions: [
new inventory.stampSheet.ConsumeItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
"#{itemSetName}",
"#{userId}"
),
],
lockTime: 50,
acquireActions: [
new inventory.stampSheet.AcquireItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
0,
false,
"",
"#{userId}"
),
]
}
),
new exchange.model.RateModel(
"material_r_to_n",
exchange.model.RateModelTimingType.AWAIT,
{
metadata: "N2R",
consumeActions: [
new inventory.stampSheet.ConsumeItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
"#{itemSetName}",
"#{userId}"
),
],
lockTime: 50,
acquireActions: [
new inventory.stampSheet.AcquireItemSetByUserId(
"namespace-0001",
"inventory-0001",
"item-0001",
1,
0,
false,
"",
"#{userId}"
),
]
}
)
],
[
]
);
}
}
console.log(new SampleStack().yaml()); // Generate Templatefrom gs2_cdk import Stack, core, exchange, inventory
class SampleStack(Stack):
def __init__(self):
super().__init__()
exchange.Namespace(
stack=self,
name="namespace-0001",
).master_data(
rate_models=[
exchange.RateModel(
name='material_n_to_r',
timing_type=exchange.RateModelTimingType.AWAIT,
options=exchange.RateModelOptions(
metadata = 'N2R',
consume_actions = [
inventory.ConsumeItemSetByUserId(
namespace_name='namespace-0001',
inventory_name='inventory-0001',
item_name='item-0001',
consume_count=1,
item_set_name='#{itemSetName}',
user_id='#{userId}'
),
],
lock_time = 50,
acquire_actions = [
inventory.AcquireItemSetByUserId(
namespace_name='namespace-0001',
inventory_name='inventory-0001',
item_name='item-0001',
acquire_count=1,
expires_at=0,
create_new_item_set=False,
item_set_name="",
user_id='#{userId}'
),
]
),
),
exchange.RateModel(
name='material_r_to_n',
timing_type=exchange.RateModelTimingType.AWAIT,
options=exchange.RateModelOptions(
metadata = 'N2R',
consume_actions = [
inventory.ConsumeItemSetByUserId(
namespace_name='namespace-0001',
inventory_name='inventory-0001',
item_name='item-0001',
consume_count=1,
item_set_name='#{itemSetName}',
user_id='#{userId}'
),
],
lock_time = 50,
acquire_actions = [
inventory.AcquireItemSetByUserId(
namespace_name='namespace-0001',
inventory_name='inventory-0001',
item_name='item-0001',
acquire_count=1,
expires_at=0,
create_new_item_set=False,
item_set_name="",
user_id='#{userId}'
),
]
),
),
],
incremental_rate_models=[
],
)
print(SampleStack().yaml()) # Generate TemplateRateModel
Exchange Rate Model
Exchange Rate Model is an entity that defines the rate used to exchange one resource for another.
In addition to the rate at which a resource can be exchanged immediately, a rate can also be set at which a resource can be exchanged after a certain amount of time in real time has elapsed. Exchange rates that after a certain period of real time has elapsed can further define the resources required to perform an immediate exchange.
| Type | Condition | Required | Default | Value Limits | Description | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| rateModelId | string | * | ~ 1024 chars | Exchange Rate Model GRN * Set automatically by the server | ||||||||
| name | string | ✓ | ~ 128 chars | Exchange Rate Model name Exchange Rate Model-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.). | ||||||||
| metadata | string | ~ 2048 chars | Metadata 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. | |||||||||
| verifyActions | List<VerifyAction> | [] | 0 ~ 10 items | List of Verify Actions Precondition checks that must all pass before the exchange is executed. If any verify action fails, the exchange is aborted without consuming resources. Used to enforce conditions such as level requirements or inventory capacity. | ||||||||
| consumeActions | List<ConsumeAction> | [] | 0 ~ 10 items | List of Consume Actions Defines the resources (cost) that the player must pay to perform this exchange. Multiple consume actions can be specified, allowing complex exchange costs such as requiring both gold and items. These actions are executed as consume actions within a distributed transaction. | ||||||||
| timingType | String Enum enum { “immediate”, “await” } | “immediate” | Type of exchange Determines when rewards are delivered after performing the exchange. immediate delivers rewards instantly upon exchange execution. await requires real-time to elapse before rewards can be claimed, creating a waiting period (e.g., crafting time).
| |||||||||
| lockTime | int | {timingType} == “await” | ✓* | 0 ~ 538214400 | Waiting time (minutes) from the execution of the exchange until the reward is actually received Only applicable when timingType is await. Specifies the number of minutes that must elapse in real time after the exchange is initiated before the player can claim the rewards. The waiting time can be shortened by using the skip mechanism.* Required if timingType is “await” | |||||||
| acquireActions | List<AcquireAction> | [] | 0 ~ 100 items | List of Acquire Actions Defines the resources (rewards) that the player receives upon completing the exchange. Multiple acquire actions can be specified to grant various resource types simultaneously. These actions are executed as acquire actions within a distributed transaction. |
AcquireAction
Acquire Action
ConsumeAction
Consume Action
VerifyAction
Verify Action
IncrementalRateModel
Incremental Cost Exchange Rate Model
Normal exchange rates always provide exchanges at a constant rate. With incremental exchange rates, you can define a rate that increases in cost as the number of exchanges increases. For example, the first exchange is performed at a rate of 1:1, but the second exchange is performed at a rate of 2:1. By defining such a rate, you can increase the value of the resources obtained by the player as the game progresses.
The number of exchanges can be reset after a certain period of real time has elapsed. This is useful for resetting the number of exchanges on a daily or weekly basis.
| Type | Condition | Required | Default | Value Limits | Description | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| incrementalRateModelId | string | * | ~ 1024 chars | Incremental Cost Exchange Rate Model GRN * Set automatically by the server | ||||||||||
| name | string | ✓ | ~ 128 chars | Incremental Cost Exchange Rate Model name Incremental Cost Exchange Rate Model-specific name. Specified using alphanumeric characters, hyphen (-), underscore (_), and period (.). | ||||||||||
| metadata | string | ~ 2048 chars | Metadata 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. | |||||||||||
| consumeAction | ConsumeAction | ✓ | Consume Action (Quantity and Value are overwritten automatically) Defines the type of resource consumed as cost for the exchange. The actual quantity is calculated dynamically based on the exchange count and the calculation type (linear, power, or script). Only the action type and target resource need to be specified; the quantity field is overwritten automatically. | |||||||||||
| calculateType | String Enum enum { “linear”, “power”, “gs2_script” } | ✓ | Calculation method for cost increase amount Determines how the exchange cost escalates with each exchange. linear calculates cost as baseValue + (coefficientValue * exchangeCount). power calculates cost as coefficientValue * (exchangeCount + 1)^2. gs2_script delegates the calculation to a custom GS2-Script for arbitrary logic.
| |||||||||||
| baseValue | long | {calculateType} == “linear” | ✓* | 0 ~ 9223372036854775805 | Base Value The initial cost for the first exchange when using the linear calculation type. The total cost is calculated as: baseValue + (coefficientValue * exchangeCount).* Required if calculateType is “linear” | |||||||||
| coefficientValue | long | {calculateType} in [“linear”, “power”] | ✓* | 0 ~ 9223372036854775805 | Coefficient Value The multiplier that controls how quickly costs escalate with each exchange. In linear mode, each exchange adds this value to the cost. In power mode, the cost is calculated as: coefficientValue * (exchangeCount + 1)^2.* Required if calculateType is “linear”,“power” | |||||||||
| calculateScriptId | string | {calculateType} == “gs2_script” | ✓* | ~ 1024 chars | GRN
of cost calculation script Script Trigger Reference - calculateCost* Required if calculateType is “gs2_script” | |||||||||
| exchangeCountId | string | ✓ | ~ 1024 chars | GS2-Limit Usage Limit Model GRN
for managing exchange execution counts References a GS2-Limit limit model that tracks how many times each user has performed this incremental exchange. The count is used to calculate the escalating cost and can be reset periodically (e.g., daily or weekly) using GS2-Limit’s reset timing. | ||||||||||
| maximumExchangeCount | int | 2147483646 | 0 ~ 2147483646 | Maximum number of exchanges The maximum number of times this incremental exchange can be performed by a user. Once the exchange count reaches this limit, further exchanges are denied until the count is reset via GS2-Limit. | ||||||||||
| acquireActions | List<AcquireAction> | [] | 0 ~ 100 items | List of Acquire Actions Defines the resources (rewards) that the player receives upon completing the incremental exchange. The rewards remain constant regardless of the exchange count; only the cost increases with each exchange. |