GS2-SkillTree SDK for Game Engine API Reference

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

Models

EzStatus

Status

Tracks the skill tree release state for a specific player and property. Maintains a list of released (unlocked) node names. Nodes can be released (added to the list), restrained (removed from the list), or reset (all cleared). Attempting to release an already-released node or restrain a non-released node results in an error. Auto-created when first accessed for a user.

Type Condition Required Default Value Limits Description
statusId string
*
~ 1024 chars Status GRN
* Set automatically by the server
userId string
~ 128 chars User ID
releasedNodeNames List<string> [] 0 ~ 1000 items Released Node Names
List of node model names that the player has unlocked in this skill tree.
Updated by release (add), restrain (remove), and reset (clear all) operations.
Maximum 1000 entries.

EzNodeModel

Node Model

Defines a node within the skill tree, including its unlock cost, prerequisites, and refund behavior. Each node can have verify actions (conditions to check before release), consume actions (costs to pay), and prerequisite nodes that must be released first. When a node is restrained (reverted to unreleased), the consumed resources are partially refunded based on the restrain return rate. The return acquire actions are automatically calculated from the consume actions multiplied by the restrain return rate.

Type Condition Required Default Value Limits Description
name string
~ 128 chars Node Model name
Node 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.
releaseVerifyActions List<EzVerifyAction> [] 0 ~ 10 items List of Release Verify Actions
List of verify actions executed before releasing this node to check whether the conditions are satisfied.
For example, can verify that the player has a certain level or possesses a specific item.
If any verify action fails, the node release is rejected. Maximum 10 actions.
releaseConsumeActions List<EzConsumeAction> [] 1 ~ 10 items Release Consume Actions
List of consume actions executed when releasing this node, representing the cost to unlock it.
These actions are also used to calculate the return acquire actions: each consume action is reverted at the restrain return rate when the node is restrained.
At least 1 consume action is required. Maximum 10 actions.
returnAcquireActions List<EzAcquireAction> 0 ~ 10 items Return Acquire Actions
List of acquire actions executed when restraining (reverting) this node, representing the resources returned to the player.
This field is auto-generated from the release consume actions multiplied by the restrain return rate.
For example, if release costs 100 gold and the return rate is 0.8, restraining returns 80 gold.
Maximum 10 actions.
restrainReturnRate float 1.0 0.0 ~ 1.0 Restrain Return Rate
The rate at which consumed resources are refunded when this node is restrained (reverted to unreleased state).
A value of 1.0 means full refund, 0.5 means half refund, and 0.0 means no refund.
Defaults to 1.0 (full refund). Valid range: 0.0 to 1.0.

EzConfig

Configuration

Configuration values applied to transaction variables

Type Condition Required Default Value Limits Description
key string
~ 64 chars Name
value string ~ 51200 chars Value

EzAcquireAction

Acquire Action

Type Condition Required Default Value Limits Description
action string (enum)
enum {
"Gs2AdReward:AcquirePointByUserId",
"Gs2Dictionary:AddEntriesByUserId",
"Gs2Enchant:ReDrawBalanceParameterStatusByUserId",
"Gs2Enchant:SetBalanceParameterStatusByUserId",
"Gs2Enchant:ReDrawRarityParameterStatusByUserId",
"Gs2Enchant:AddRarityParameterStatusByUserId",
"Gs2Enchant:SetRarityParameterStatusByUserId",
"Gs2Enhance:DirectEnhanceByUserId",
"Gs2Enhance:UnleashByUserId",
"Gs2Enhance:CreateProgressByUserId",
"Gs2Exchange:ExchangeByUserId",
"Gs2Exchange:IncrementalExchangeByUserId",
"Gs2Exchange:CreateAwaitByUserId",
"Gs2Exchange:AcquireForceByUserId",
"Gs2Exchange:SkipByUserId",
"Gs2Experience:AddExperienceByUserId",
"Gs2Experience:SetExperienceByUserId",
"Gs2Experience:AddRankCapByUserId",
"Gs2Experience:SetRankCapByUserId",
"Gs2Experience:MultiplyAcquireActionsByUserId",
"Gs2Formation:AddMoldCapacityByUserId",
"Gs2Formation:SetMoldCapacityByUserId",
"Gs2Formation:AcquireActionsToFormProperties",
"Gs2Formation:SetFormByUserId",
"Gs2Formation:AcquireActionsToPropertyFormProperties",
"Gs2Friend:UpdateProfileByUserId",
"Gs2Grade:AddGradeByUserId",
"Gs2Grade:ApplyRankCapByUserId",
"Gs2Grade:MultiplyAcquireActionsByUserId",
"Gs2Guild:IncreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Guild:SetMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:IncreaseMaximumIdleMinutesByUserId",
"Gs2Idle:SetMaximumIdleMinutesByUserId",
"Gs2Idle:ReceiveByUserId",
"Gs2Inbox:SendMessageByUserId",
"Gs2Inventory:AddCapacityByUserId",
"Gs2Inventory:SetCapacityByUserId",
"Gs2Inventory:AcquireItemSetByUserId",
"Gs2Inventory:AcquireItemSetWithGradeByUserId",
"Gs2Inventory:AddReferenceOfByUserId",
"Gs2Inventory:DeleteReferenceOfByUserId",
"Gs2Inventory:AcquireSimpleItemsByUserId",
"Gs2Inventory:SetSimpleItemsByUserId",
"Gs2Inventory:AcquireBigItemByUserId",
"Gs2Inventory:SetBigItemByUserId",
"Gs2JobQueue:PushByUserId",
"Gs2Limit:CountDownByUserId",
"Gs2Limit:DeleteCounterByUserId",
"Gs2LoginReward:DeleteReceiveStatusByUserId",
"Gs2LoginReward:UnmarkReceivedByUserId",
"Gs2Lottery:DrawByUserId",
"Gs2Lottery:ResetBoxByUserId",
"Gs2Mission:RevertReceiveByUserId",
"Gs2Mission:IncreaseCounterByUserId",
"Gs2Mission:SetCounterByUserId",
"Gs2Money:DepositByUserId",
"Gs2Money:RevertRecordReceipt",
"Gs2Money2:DepositByUserId",
"Gs2Quest:CreateProgressByUserId",
"Gs2Schedule:TriggerByUserId",
"Gs2Schedule:ExtendTriggerByUserId",
"Gs2Script:InvokeScript",
"Gs2SerialKey:RevertUseByUserId",
"Gs2SerialKey:IssueOnce",
"Gs2Showcase:DecrementPurchaseCountByUserId",
"Gs2Showcase:ForceReDrawByUserId",
"Gs2SkillTree:MarkReleaseByUserId",
"Gs2Stamina:RecoverStaminaByUserId",
"Gs2Stamina:RaiseMaxValueByUserId",
"Gs2Stamina:SetMaxValueByUserId",
"Gs2Stamina:SetRecoverIntervalByUserId",
"Gs2Stamina:SetRecoverValueByUserId",
"Gs2StateMachine:StartStateMachineByUserId",
}
Type of Acquire Action
request string
~ 524288 chars JSON string of the request used when executing the action

EzConsumeAction

Consume Action

Type Condition Required Default Value Limits Description
action string (enum)
enum {
"Gs2AdReward:ConsumePointByUserId",
"Gs2Dictionary:DeleteEntriesByUserId",
"Gs2Enhance:DeleteProgressByUserId",
"Gs2Exchange:DeleteAwaitByUserId",
"Gs2Experience:SubExperienceByUserId",
"Gs2Experience:SubRankCapByUserId",
"Gs2Formation:SubMoldCapacityByUserId",
"Gs2Grade:SubGradeByUserId",
"Gs2Guild:DecreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:DecreaseMaximumIdleMinutesByUserId",
"Gs2Inbox:OpenMessageByUserId",
"Gs2Inbox:DeleteMessageByUserId",
"Gs2Inventory:ConsumeItemSetByUserId",
"Gs2Inventory:ConsumeSimpleItemsByUserId",
"Gs2Inventory:ConsumeBigItemByUserId",
"Gs2JobQueue:DeleteJobByUserId",
"Gs2Limit:CountUpByUserId",
"Gs2LoginReward:MarkReceivedByUserId",
"Gs2Mission:ReceiveByUserId",
"Gs2Mission:BatchReceiveByUserId",
"Gs2Mission:DecreaseCounterByUserId",
"Gs2Mission:ResetCounterByUserId",
"Gs2Money:WithdrawByUserId",
"Gs2Money:RecordReceipt",
"Gs2Money2:WithdrawByUserId",
"Gs2Money2:VerifyReceiptByUserId",
"Gs2Quest:DeleteProgressByUserId",
"Gs2Ranking2:CreateGlobalRankingReceivedRewardByUserId",
"Gs2Ranking2:CreateClusterRankingReceivedRewardByUserId",
"Gs2Schedule:DeleteTriggerByUserId",
"Gs2SerialKey:UseByUserId",
"Gs2Showcase:IncrementPurchaseCountByUserId",
"Gs2SkillTree:MarkRestrainByUserId",
"Gs2Stamina:DecreaseMaxValueByUserId",
"Gs2Stamina:ConsumeStaminaByUserId",
}
Type of Consume Action
request string
~ 524288 chars JSON string of the request used when executing the action

EzVerifyAction

Verify Action

Type Condition Required Default Value Limits Description
action string (enum)
enum {
"Gs2Dictionary:VerifyEntryByUserId",
"Gs2Distributor:IfExpressionByUserId",
"Gs2Distributor:AndExpressionByUserId",
"Gs2Distributor:OrExpressionByUserId",
"Gs2Enchant:VerifyRarityParameterStatusByUserId",
"Gs2Experience:VerifyRankByUserId",
"Gs2Experience:VerifyRankCapByUserId",
"Gs2Grade:VerifyGradeByUserId",
"Gs2Grade:VerifyGradeUpMaterialByUserId",
"Gs2Guild:VerifyCurrentMaximumMemberCountByGuildName",
"Gs2Guild:VerifyIncludeMemberByUserId",
"Gs2Inventory:VerifyInventoryCurrentMaxCapacityByUserId",
"Gs2Inventory:VerifyItemSetByUserId",
"Gs2Inventory:VerifyReferenceOfByUserId",
"Gs2Inventory:VerifySimpleItemByUserId",
"Gs2Inventory:VerifyBigItemByUserId",
"Gs2Limit:VerifyCounterByUserId",
"Gs2Matchmaking:VerifyIncludeParticipantByUserId",
"Gs2Mission:VerifyCompleteByUserId",
"Gs2Mission:VerifyCounterValueByUserId",
"Gs2Ranking2:VerifyGlobalRankingScoreByUserId",
"Gs2Ranking2:VerifyClusterRankingScoreByUserId",
"Gs2Ranking2:VerifySubscribeRankingScoreByUserId",
"Gs2Schedule:VerifyTriggerByUserId",
"Gs2Schedule:VerifyEventByUserId",
"Gs2SerialKey:VerifyCodeByUserId",
"Gs2Stamina:VerifyStaminaValueByUserId",
"Gs2Stamina:VerifyStaminaMaxValueByUserId",
"Gs2Stamina:VerifyStaminaRecoverIntervalMinutesByUserId",
"Gs2Stamina:VerifyStaminaRecoverValueByUserId",
"Gs2Stamina:VerifyStaminaOverflowValueByUserId",
}
Type of Verify Action
request string
~ 524288 chars JSON string of the request used when executing the action

EzVerifyActionResult

Verify Action execution result

Type Condition Required Default Value Limits Description
action string (enum)
enum {
"Gs2Dictionary:VerifyEntryByUserId",
"Gs2Distributor:IfExpressionByUserId",
"Gs2Distributor:AndExpressionByUserId",
"Gs2Distributor:OrExpressionByUserId",
"Gs2Enchant:VerifyRarityParameterStatusByUserId",
"Gs2Experience:VerifyRankByUserId",
"Gs2Experience:VerifyRankCapByUserId",
"Gs2Grade:VerifyGradeByUserId",
"Gs2Grade:VerifyGradeUpMaterialByUserId",
"Gs2Guild:VerifyCurrentMaximumMemberCountByGuildName",
"Gs2Guild:VerifyIncludeMemberByUserId",
"Gs2Inventory:VerifyInventoryCurrentMaxCapacityByUserId",
"Gs2Inventory:VerifyItemSetByUserId",
"Gs2Inventory:VerifyReferenceOfByUserId",
"Gs2Inventory:VerifySimpleItemByUserId",
"Gs2Inventory:VerifyBigItemByUserId",
"Gs2Limit:VerifyCounterByUserId",
"Gs2Matchmaking:VerifyIncludeParticipantByUserId",
"Gs2Mission:VerifyCompleteByUserId",
"Gs2Mission:VerifyCounterValueByUserId",
"Gs2Ranking2:VerifyGlobalRankingScoreByUserId",
"Gs2Ranking2:VerifyClusterRankingScoreByUserId",
"Gs2Ranking2:VerifySubscribeRankingScoreByUserId",
"Gs2Schedule:VerifyTriggerByUserId",
"Gs2Schedule:VerifyEventByUserId",
"Gs2SerialKey:VerifyCodeByUserId",
"Gs2Stamina:VerifyStaminaValueByUserId",
"Gs2Stamina:VerifyStaminaMaxValueByUserId",
"Gs2Stamina:VerifyStaminaRecoverIntervalMinutesByUserId",
"Gs2Stamina:VerifyStaminaRecoverValueByUserId",
"Gs2Stamina:VerifyStaminaOverflowValueByUserId",
}
Type of Verify Action
verifyRequest string
~ 524288 chars JSON string of the request used when executing the action
statusCode int 0 ~ 999 Status code
verifyResult string ~ 1048576 chars Result content

EzConsumeActionResult

Consume Action execution result

Type Condition Required Default Value Limits Description
action string (enum)
enum {
"Gs2AdReward:ConsumePointByUserId",
"Gs2Dictionary:DeleteEntriesByUserId",
"Gs2Enhance:DeleteProgressByUserId",
"Gs2Exchange:DeleteAwaitByUserId",
"Gs2Experience:SubExperienceByUserId",
"Gs2Experience:SubRankCapByUserId",
"Gs2Formation:SubMoldCapacityByUserId",
"Gs2Grade:SubGradeByUserId",
"Gs2Guild:DecreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:DecreaseMaximumIdleMinutesByUserId",
"Gs2Inbox:OpenMessageByUserId",
"Gs2Inbox:DeleteMessageByUserId",
"Gs2Inventory:ConsumeItemSetByUserId",
"Gs2Inventory:ConsumeSimpleItemsByUserId",
"Gs2Inventory:ConsumeBigItemByUserId",
"Gs2JobQueue:DeleteJobByUserId",
"Gs2Limit:CountUpByUserId",
"Gs2LoginReward:MarkReceivedByUserId",
"Gs2Mission:ReceiveByUserId",
"Gs2Mission:BatchReceiveByUserId",
"Gs2Mission:DecreaseCounterByUserId",
"Gs2Mission:ResetCounterByUserId",
"Gs2Money:WithdrawByUserId",
"Gs2Money:RecordReceipt",
"Gs2Money2:WithdrawByUserId",
"Gs2Money2:VerifyReceiptByUserId",
"Gs2Quest:DeleteProgressByUserId",
"Gs2Ranking2:CreateGlobalRankingReceivedRewardByUserId",
"Gs2Ranking2:CreateClusterRankingReceivedRewardByUserId",
"Gs2Schedule:DeleteTriggerByUserId",
"Gs2SerialKey:UseByUserId",
"Gs2Showcase:IncrementPurchaseCountByUserId",
"Gs2SkillTree:MarkRestrainByUserId",
"Gs2Stamina:DecreaseMaxValueByUserId",
"Gs2Stamina:ConsumeStaminaByUserId",
}
Type of Consume Action
consumeRequest string
~ 524288 chars JSON string of the request used when executing the action
statusCode int 0 ~ 999 Status code
consumeResult string ~ 1048576 chars Result content

EzAcquireActionResult

Acquire Action execution result

Type Condition Required Default Value Limits Description
action string (enum)
enum {
"Gs2AdReward:AcquirePointByUserId",
"Gs2Dictionary:AddEntriesByUserId",
"Gs2Enchant:ReDrawBalanceParameterStatusByUserId",
"Gs2Enchant:SetBalanceParameterStatusByUserId",
"Gs2Enchant:ReDrawRarityParameterStatusByUserId",
"Gs2Enchant:AddRarityParameterStatusByUserId",
"Gs2Enchant:SetRarityParameterStatusByUserId",
"Gs2Enhance:DirectEnhanceByUserId",
"Gs2Enhance:UnleashByUserId",
"Gs2Enhance:CreateProgressByUserId",
"Gs2Exchange:ExchangeByUserId",
"Gs2Exchange:IncrementalExchangeByUserId",
"Gs2Exchange:CreateAwaitByUserId",
"Gs2Exchange:AcquireForceByUserId",
"Gs2Exchange:SkipByUserId",
"Gs2Experience:AddExperienceByUserId",
"Gs2Experience:SetExperienceByUserId",
"Gs2Experience:AddRankCapByUserId",
"Gs2Experience:SetRankCapByUserId",
"Gs2Experience:MultiplyAcquireActionsByUserId",
"Gs2Formation:AddMoldCapacityByUserId",
"Gs2Formation:SetMoldCapacityByUserId",
"Gs2Formation:AcquireActionsToFormProperties",
"Gs2Formation:SetFormByUserId",
"Gs2Formation:AcquireActionsToPropertyFormProperties",
"Gs2Friend:UpdateProfileByUserId",
"Gs2Grade:AddGradeByUserId",
"Gs2Grade:ApplyRankCapByUserId",
"Gs2Grade:MultiplyAcquireActionsByUserId",
"Gs2Guild:IncreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Guild:SetMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:IncreaseMaximumIdleMinutesByUserId",
"Gs2Idle:SetMaximumIdleMinutesByUserId",
"Gs2Idle:ReceiveByUserId",
"Gs2Inbox:SendMessageByUserId",
"Gs2Inventory:AddCapacityByUserId",
"Gs2Inventory:SetCapacityByUserId",
"Gs2Inventory:AcquireItemSetByUserId",
"Gs2Inventory:AcquireItemSetWithGradeByUserId",
"Gs2Inventory:AddReferenceOfByUserId",
"Gs2Inventory:DeleteReferenceOfByUserId",
"Gs2Inventory:AcquireSimpleItemsByUserId",
"Gs2Inventory:SetSimpleItemsByUserId",
"Gs2Inventory:AcquireBigItemByUserId",
"Gs2Inventory:SetBigItemByUserId",
"Gs2JobQueue:PushByUserId",
"Gs2Limit:CountDownByUserId",
"Gs2Limit:DeleteCounterByUserId",
"Gs2LoginReward:DeleteReceiveStatusByUserId",
"Gs2LoginReward:UnmarkReceivedByUserId",
"Gs2Lottery:DrawByUserId",
"Gs2Lottery:ResetBoxByUserId",
"Gs2Mission:RevertReceiveByUserId",
"Gs2Mission:IncreaseCounterByUserId",
"Gs2Mission:SetCounterByUserId",
"Gs2Money:DepositByUserId",
"Gs2Money:RevertRecordReceipt",
"Gs2Money2:DepositByUserId",
"Gs2Quest:CreateProgressByUserId",
"Gs2Schedule:TriggerByUserId",
"Gs2Schedule:ExtendTriggerByUserId",
"Gs2Script:InvokeScript",
"Gs2SerialKey:RevertUseByUserId",
"Gs2SerialKey:IssueOnce",
"Gs2Showcase:DecrementPurchaseCountByUserId",
"Gs2Showcase:ForceReDrawByUserId",
"Gs2SkillTree:MarkReleaseByUserId",
"Gs2Stamina:RecoverStaminaByUserId",
"Gs2Stamina:RaiseMaxValueByUserId",
"Gs2Stamina:SetMaxValueByUserId",
"Gs2Stamina:SetRecoverIntervalByUserId",
"Gs2Stamina:SetRecoverValueByUserId",
"Gs2StateMachine:StartStateMachineByUserId",
}
Type of Acquire Action
acquireRequest string
~ 524288 chars JSON string of the request used when executing the action
statusCode int 0 ~ 999 Status code
acquireResult string ~ 1048576 chars Result content

EzTransactionResult

Transaction execution result

Result of a transaction executed using the server-side automatic execution feature

Type Condition Required Default Value Limits Description
transactionId string
36 ~ 36 chars Transaction ID
verifyResults List<EzVerifyActionResult> 0 ~ 10 items List of verify action execution results
consumeResults List<EzConsumeActionResult> [] 0 ~ 10 items List of Consume Action execution results
acquireResults List<EzAcquireActionResult> [] 0 ~ 100 items List of Acquire Action execution results

Methods

getNodeModel

Get the details of a specific skill tree node

Retrieves a single node definition by name, including its prerequisites, release cost, and refund settings.

Use this to display detailed information when the player taps on a node in the skill tree — for example:

  • “Power Strike” — Requires: Basic Attack (released). Cost: 3 Skill Points. Effect: +50% attack damage.
  • If the node has a restrain return rate of 80%, the player gets back 80% of the cost when reverting this node.

The response includes:

  • Prerequisite node names: The list of nodes that must be released first
  • Release consume actions: What the player pays to unlock (e.g., spend 3 skill points)
  • Release verify actions: Conditions checked before allowing release (e.g., player level >= 10)
  • Restrain return rate: The percentage of resources refunded when the node is reverted (0.0 to 1.0)

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
nodeModelName string
~ 128 chars Node Model name
Node Model-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).

Result

Type Description
item EzNodeModel Node Model

Implementation Example

    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).NodeModel(
        nodeModelName: "status-0001"
    );
    var item = await domain.ModelAsync();
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).NodeModel(
        nodeModelName: "status-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->NodeModel(
        "status-0001" // nodeModelName
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
Value change event handling
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).NodeModel(
        nodeModelName: "status-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.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).NodeModel(
        nodeModelName: "status-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->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->NodeModel(
        "status-0001" // nodeModelName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::SkillTree::Model::FNodeModel> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

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

listNodeModels

Get a list of all skill tree nodes

Retrieves all node definitions in the skill tree. Each node represents a skill, ability, or upgrade that the player can unlock (release) by spending resources.

A skill tree is a branching structure where nodes have prerequisites — you must unlock earlier nodes before you can unlock later ones. For example: “Basic Attack” → “Power Strike” → “Critical Slash”, where each node requires the previous one to be released first.

Each node definition includes:

  • Prerequisite nodes: Which other nodes must be released before this one can be unlocked
  • Release cost: What resources the player must spend to unlock this node (e.g., skill points, gold, materials)
  • Release conditions: Any additional requirements that must be met (e.g., minimum level)
  • Restrain return rate: What percentage of resources is refunded if the player later reverts (locks) this node

Use this to build the skill tree UI — draw all nodes, connect them based on prerequisites, and show which ones are available for release.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).

Result

Type Description
items List<EzNodeModel> List of Node Models

Implementation Example

    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    );
    var items = await domain.NodeModelsAsync(
    ).ToListAsync();
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    );
    var it = domain.NodeModels(
    );
    List<EzNodeModel> items = new List<EzNodeModel>();
    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->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    );
    const auto It = Domain->NodeModels(
    );
    TArray<Gs2::UE5::SkillTree::Model::FEzNodeModelPtr> Result;
    for (auto Item : *It)
    {
        if (Item.IsError())
        {
            return false;
        }
        Result.Add(Item.Current());
    }
Value change event handling
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    );
    
    // Start event handling
    var callbackId = domain.SubscribeNodeModels(
        () => {
            // Called when an element of the list changes.
        }
    );

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

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

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

getStatus

Get the player’s skill tree progress

Retrieves which nodes the player has released (unlocked) in the skill tree for the specified property ID.

The propertyId identifies which skill tree instance to look up. If your game has one skill tree per character, the propertyId could be the character ID. For example, a warrior character and a mage character would each have their own skill tree progress tracked by different propertyIds.

Use this to render the skill tree screen — combine with ListNodeModels to get the full tree structure, then overlay the player’s release status to show:

  • Released nodes (unlocked, highlighted)
  • Available nodes (prerequisites met, can be released next)
  • Locked nodes (prerequisites not yet met, greyed out)

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
propertyId string
~ 1024 chars Property 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.

Result

Type Description
item EzStatus Status

Implementation Example

    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var item = await domain.ModelAsync();
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var future = domain.ModelFuture();
    yield return future;
    var item = future.Result;
    const auto Domain = Gs2->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "property-0001" // propertyId
    );
    const auto Future = Domain->Model();
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }
Value change event handling
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-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.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-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->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "property-0001" // propertyId
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::SkillTree::Model::FStatus> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

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

release

Unlock nodes in the skill tree

Releases (unlocks) one or more nodes in the skill tree. The player spends the required resources and the nodes become active.

This is the “Learn Skill” or “Unlock” button in your skill tree UI. When the player taps a node they want to unlock:

  1. The system checks that all prerequisite nodes are already released
  2. The system checks release conditions (verify actions) — e.g., minimum player level
  3. The system deducts the release cost (consume actions) — e.g., 3 skill points
  4. The node is marked as released

You can release multiple nodes at once by passing multiple node names. All prerequisites and costs are validated for each node.

If any prerequisite is not met, or the player doesn’t have enough resources, the release fails and no resources are consumed.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
nodeModelNames List<string>
1 ~ 1000 items List of Node Model names
propertyId string
~ 1024 chars Property 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.

Result

Type Description
item EzStatus Status
transactionId string Issued transaction ID
stampSheet string Stamp sheet used to execute the release process
stampSheetEncryptionKeyId string Cryptographic key GRN used for stamp sheet signature calculations
autoRunStampSheet bool Whether automatic transaction execution is enabled
atomicCommit bool Whether to commit the transaction atomically
transaction string Issued transaction
transactionResult EzTransactionResult Transaction execution result

Implementation Example

    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var result = await domain.ReleaseAsync(
        nodeModelNames: new List<string> {
            "node-0001",
        }
    );
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var future = domain.ReleaseFuture(
        nodeModelNames: new List<string> {
            "node-0001",
        }
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().
    const auto Domain = Gs2->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "property-0001" // propertyId
    );
    const auto Future = Domain->Release(
        []
        {
            auto v = TOptional<TArray<FString>>();
            v->Add("node-0001");
            return v;
        }() // nodeModelNames
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

reset

Reset the entire skill tree (full respec)

Reverts ALL released nodes in the skill tree back to unreleased state at once. Resources are refunded based on each node’s restrain return rate.

This is the “Reset All Skills” or “Full Respec” button — the player starts their skill tree over from scratch.

For example, if a player has released 10 nodes with various costs, all 10 are reverted and the player receives partial refunds for each one based on the configured return rates.

Common use cases:

  • A “Respec” feature that lets players rebuild their skill tree with a different strategy
  • Seasonal resets where all players start fresh
  • When game balance changes make the current build suboptimal and you want to let players readjust

Unlike Restrain (which selectively reverts specific nodes), Reset affects the entire tree regardless of dependencies.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
propertyId string
~ 1024 chars Property 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.

Result

Type Description
item EzStatus Status
transactionId string Issued transaction ID
stampSheet string Stamp sheet used to execute the reset process
stampSheetEncryptionKeyId string Cryptographic key GRN used for stamp sheet signature calculations
autoRunStampSheet bool Whether automatic transaction execution is enabled
atomicCommit bool Whether to commit the transaction atomically
transaction string Issued transaction
transactionResult EzTransactionResult Transaction execution result

Implementation Example

    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var result = await domain.ResetAsync(
    );
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var future = domain.ResetFuture(
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().
    const auto Domain = Gs2->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "property-0001" // propertyId
    );
    const auto Future = Domain->Reset(
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }

restrain

Revert specific nodes back to locked state

Reverts (locks) one or more released nodes back to unreleased state. A portion of the resources spent on releasing these nodes is refunded based on each node’s restrain return rate.

This is a “partial respec” feature — instead of resetting the entire skill tree, the player can selectively undo specific nodes.

For example, if a node cost 100 Gold to release and has a restrain return rate of 0.8 (80%), the player gets back 80 Gold when restraining it.

Important rules:

  • You cannot restrain a node if other released nodes depend on it (i.e., nodes that list it as a prerequisite)
  • To restrain a node that is a prerequisite for other released nodes, you must restrain the dependent nodes first
  • This ensures the skill tree always remains in a valid state (no orphaned nodes)

Use this for a “remove skill” or “undo” feature in your skill tree UI.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
nodeModelNames List<string>
1 ~ 1000 items List of Node Model names
propertyId string
~ 1024 chars Property 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.

Result

Type Description
item EzStatus Status
transactionId string Issued transaction ID
stampSheet string Stamp sheet used to execute the restrain process
stampSheetEncryptionKeyId string Cryptographic key GRN used for stamp sheet signature calculations
autoRunStampSheet bool Whether automatic transaction execution is enabled
atomicCommit bool Whether to commit the transaction atomically
transaction string Issued transaction
transactionResult EzTransactionResult Transaction execution result

Implementation Example

    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var result = await domain.RestrainAsync(
        nodeModelNames: new List<string> {
            "node-0001",
        }
    );
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().
    var domain = gs2.SkillTree.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        propertyId: "property-0001"
    );
    var future = domain.RestrainFuture(
        nodeModelNames: new List<string> {
            "node-0001",
        }
    );
    yield return future;
    if (future.Error != null)
    {
        onError.Invoke(future.Error, null);
        yield break;
    }
    // In New Experience, stamp sheets are automatically executed at the SDK level.
    // If an error occurs, a TransactionException is thrown.
    // You can retry with TransactionException::Retry().
    const auto Domain = Gs2->SkillTree->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "property-0001" // propertyId
    );
    const auto Future = Domain->Restrain(
        []
        {
            auto v = TOptional<TArray<FString>>();
            v->Add("node-0001");
            return v;
        }() // nodeModelNames
    );
    Future->StartSynchronousTask();
    if (Future->GetTask().IsError())
    {
        return false;
    }