Documentation index for AI agents

GS2-SkillTree Transaction Actions

Specification of verify/consume/acquire transaction actions

Combining actions, and concurrency

The background common to every service is collected in Combining Transaction Actions. Read that first; the rest of this section is what GS2-SkillTree adds to it.

The transaction actions of GS2-SkillTree address one status, identified by the combination of namespace, user, and property. A status records which nodes of the skill tree have been released, and it is rewritten as a whole on every update.

OperationRepeated in one transactionAcross a nested transactionBoundary that separates targets
Releasing nodes
MarkReleaseByUserId
Combined, with node names concatenated and duplicates removedFailsnamespace, user, property
Restraining nodes
MarkRestrainByUserId
Combined, with node names concatenated and duplicates removedFailsnamespace, user, property

Releasing a node comes with paying whatever that node requires, and restraining it returns that payment. Those payments and returns are issued as a transaction of their own, so the restrictions of whichever services they belong to apply.

The return is derived from the payment: each consume action of the release is turned into the acquire action that undoes it. A reset processes every released node at once, so returns derived from different nodes end up gathered into one transaction. If two nodes take Gs2Mission:ReceiveByUserId for different tasks of the same mission group, for instance, the two returns collide and the restrain or the reset fails.

To release several nodes that do not depend on each other, list them in the nodeModelNames of a single action, or specify several actions and let them be combined; both work.

Releasing a node together with its prerequisite requires putting them in one action. Releasing a node checks that its prerequisites are already released, and that check is made against the status as of the start of the transaction, so splitting them into two actions leaves the release of the prerequisite invisible to the other one.

Releasing and restraining are separate rows sharing a boundary, so they cannot go in one transaction. Split the transaction.

A different property is a different status, so releasing nodes on several properties in one transaction is fine.

Take care with nested transactions

Even two releases on the same status, which would have been combined into one if written side by side, make the transaction fail when one of them arrives from the inside.

If you want to avoid these restrictions

Releasing a node is an acquire action and restraining one is a consume action. Turning acquireActionUseJobQueue on clears collisions between releases, but a release together with a restrain needs enableAtomicCommit turned off. To release a node and its prerequisite together, listing them in one action stays the reliable way whichever setting you use.

Concurrency and retries

Where several requests update the same status at the same time, the one confirmed later returns a conflict (409). Nothing is wrong with the request, so retrying will succeed, and the prerequisites are re-checked against the latest status on the retry.

Releasing nodes on different properties at the same time does not conflict.


Consume Action

Gs2SkillTree:MarkRestrainByUserId

Revert a node to unreleased state by User ID

Validates that the specified nodes can be restrained (no dependent nodes must be in released state), then marks them as unreleased.

Quantity specification supported: NO

Reversible action: YES

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
propertyIdstring
~ 1024 charsProperty ID
An identifier that allows multiple independent skill tree instances per user.
Enables scenarios where a player has separate skill trees for different characters or contexts within the same Namespace.
Maximum 1024 characters.
nodeModelNamesList<string>
1 ~ 1000 itemsList of node model names
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2SkillTree:MarkRestrainByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "propertyId": "[string]Property ID",
        "nodeModelNames": [
            "[string]Node Model name"
        ],
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2SkillTree:MarkRestrainByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  propertyId: "[string]Property ID"
  nodeModelNames: 
    - "[string]Node Model name"
  timeOffsetToken: "[string]Time offset token"
transaction.service("skillTree").consume.mark_restrain_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    propertyId="[string]Property ID",
    nodeModelNames={
        "[string]Node Model name"
    },
    timeOffsetToken="[string]Time offset token",
})

Acquire Action

Gs2SkillTree:MarkReleaseByUserId

Mark a node as released by User ID

Validates that the specified nodes can be released (prerequisite nodes must already be released), then marks them as released.

Quantity specification supported: NO

Reversible action: YES

TypeConditionRequiredDefaultValue LimitsDescription
namespaceNamestring
~ 128 charsNamespace name
Unique Namespace name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
userIdstring
~ 128 charsUser ID
Specify #{userId} to substitute the currently logged-in user’s ID.
propertyIdstring
~ 1024 charsProperty ID
An identifier that allows multiple independent skill tree instances per user.
Enables scenarios where a player has separate skill trees for different characters or contexts within the same Namespace.
Maximum 1024 characters.
nodeModelNamesList<string>
1 ~ 1000 itemsList of Node Model names
timeOffsetTokenstring~ 1024 charsTime offset token
{
    "action": "Gs2SkillTree:MarkReleaseByUserId",
    "request": {
        "namespaceName": "[string]Namespace name",
        "userId": "[string]User ID",
        "propertyId": "[string]Property ID",
        "nodeModelNames": [
            "[string]Node Model name"
        ],
        "timeOffsetToken": "[string]Time offset token"
    }
}
action: Gs2SkillTree:MarkReleaseByUserId
request:
  namespaceName: "[string]Namespace name"
  userId: "[string]User ID"
  propertyId: "[string]Property ID"
  nodeModelNames: 
    - "[string]Node Model name"
  timeOffsetToken: "[string]Time offset token"
transaction.service("skillTree").acquire.mark_release_by_user_id({
    namespaceName="[string]Namespace name",
    userId="[string]User ID",
    propertyId="[string]Property ID",
    nodeModelNames={
        "[string]Node Model name"
    },
    timeOffsetToken="[string]Time offset token",
})