View Format: Multi-Page Single Page

Simple Skill Forge

Generate Complete Skill Databases, Skill Trees, Loadouts, and Combos in Minutes.

Overview

The Skill Tree Forge generates skill tree databases — grid-based talent trees where nodes reference skills from Skill Forge databases and are connected by directed parent-child edges. Each tree supports branch groups for specialization paths, point costs, level requirements, and single-level dynamic properties.

Generated databases implement ISimpleSkillTreeDataSource and produce the same 4-file output as the Skill Forge (enum, database, editor, asset), with the suffix Tree (e.g., ARPGTreeType.cs, ARPGTreeDatabase.cs).

Open the Skill Tree Forge wizard from the Unity menu:

Window > Living Failure > Simple Skill Forge > Skill Tree Forge

Key features:

  • Grid-based node layout with row/column positioning
  • Parent-child connections enforcing unlock order
  • Branch groups for specialization paths (e.g., "Fire", "Ice", "Lightning")
  • Per-node point cost, required level, and required points in tree
  • Nodes reference skill codes from any linked Skill Forge database
  • Single-level dynamic properties on each tree
  • Runtime tracker with unlock/reset/snapshot support
  • Character class restrictions via SAF Character Templates

The 5-Step Wizard

The Skill Tree Forge follows the same 5-step wizard pattern as all forges.

Step 1: Setup

Configure the database name, namespace, class prefix, and template. The Skill Tree Forge adds a Linked Skill Databases section where you drag-and-drop Skill Forge database assets. Linking a skill database enables searchable dropdown menus for node skillCode fields in Step 3. You can link multiple skill databases.

You can also link SAF Character Template assets for class restriction support.

Auto-naming: The Skill Tree Forge offers auto-naming based on your database name. For example, entering ARPG generates ARPGTreeType, ARPGTreeDatabase, etc.

Step 2: Definitions

Define single-level dynamic properties for your trees. Unlike the Skill Forge, there is no rank-level — properties apply to the tree definition itself (e.g., "Tree Type", "Total Point Cap", "Is Starter Tree"). The JSON schema export/import section is available for AI-assisted content generation.

Step 3: Builder

Split-panel editor (280px left panel). The left panel lists all tree definitions with search, filter, sort, bulk operations, and pagination. The right panel shows foldout sections for:

  • Identity — code, display name, description, icon
  • Categories / Flags / Numerics / Texts — single-level properties
  • Nodes — ReorderableList of tree nodes (9 editable fields per node)
  • Connections — ReorderableList of directed edges (from/to node dropdowns)
  • Character Class Restrictions — allowed character classes

Step 4: Settings

Output paths, custom paths toggle, generation toggles, and file preview.

Step 5: Generate

Two-phase generation producing {Prefix}TreeType.cs, {Prefix}TreeDatabase.cs, {Prefix}TreeDatabaseEditor.cs, and the .asset file.

Nodes

Each tree contains an array of SimpleSkillTreeNode structs. A node represents a single unlockable entry in the tree, referencing a skill from a linked Skill Forge database.

Field Type Description
nodeId int Unique identifier within this tree (auto-assigned)
skillCode string Skill code referencing a Skill Forge database entry
row int Row position in the tree grid (for visual layout)
column int Column position in the tree grid (for visual layout)
pointCost int Skill points required to unlock this node
requiredLevel int Minimum character level required to unlock this node
requiredPointsInTree int Minimum total points already spent in this tree to unlock
branchGroup string Specialization path identifier (e.g., "Fire", "Ice"). Nodes with the same branchGroup form a specialization track. Empty = no specific branch.
isRequired bool Whether this node must be unlocked to proceed further down its branch

Querying Nodes

// Get all nodes for a tree SimpleSkillTreeNode[] nodes = database.GetNodesForTree("WARRIOR_COMBAT"); // Get a node by ID from the tree struct SimpleSkillTreeNode? node = tree.GetNodeById(5); // Get root nodes (no parent connections) SimpleSkillTreeNode[] roots = tree.GetRootNodes(); // Get nodes in a specific branch SimpleSkillTreeNode[] fireNodes = tree.GetNodesInBranch("Fire"); // Get all unique branch groups string[] branches = tree.GetBranchGroups(); // Also available at the database level: string[] dbBranches = database.GetBranchGroups("WARRIOR_COMBAT"); // Check if a tree contains a specific skill bool hasFireball = tree.ContainsSkill("FIREBALL"); // Find all trees containing a skill SimpleSkillTreeDefinition[] treesWithFireball = database.FindTreesContainingSkill("FIREBALL");

Connections

Connections are directed edges (SimpleSkillTreeConnection) that define parent-child unlock dependencies between nodes. A child node cannot be unlocked until all parent nodes are unlocked.

Field Type Description
fromNodeId int Parent node ID (must be unlocked first)
toNodeId int Child node ID (unlockable after parent)

Querying Connections

// Get all connections for a tree SimpleSkillTreeConnection[] connections = database.GetConnectionsForTree("WARRIOR_COMBAT"); // Get connections from/to a specific node SimpleSkillTreeConnection[] children = tree.GetConnectionsFrom(nodeId); SimpleSkillTreeConnection[] parents = tree.GetConnectionsTo(nodeId); // Get parent/child node IDs directly int[] parentIds = tree.GetParentNodeIds(nodeId); int[] childIds = tree.GetChildNodeIds(nodeId);

Single-Level Properties

Skill trees use single-level dynamic properties (Categories, Flags, Numerics, Texts) on the tree definition itself. There is no child-level like the Skill Forge's rank-level properties.

// Access tree-level properties int treeType = tree.GetCategoryValue(0); bool isStarterTree = tree.GetFlagValue(0); float pointCap = tree.GetNumericValue(0); string lore = tree.GetTextValue(0); // Get property definition labels string[] catLabels = database.GetCategoryLabels(); // e.g., ["Tree Type", "Specialization"] string[] catEntries = database.GetCategoryEntries(0); // e.g., ["Class", "Subclass", "Universal"] string[] flagNames = database.GetFlagNames(); // e.g., ["Is Starter Tree", "Requires Mastery"] string[] numNames = database.GetNumericNames(); // e.g., ["Total Point Cap", "Required Level"] string[] textNames = database.GetTextNames(); // e.g., ["Tree Description", "Lore"] // Filter trees by property values SimpleSkillTreeDefinition[] classTrees = database.GetTreesByCategory(0, 0); SimpleSkillTreeDefinition[] starterTrees = database.GetTreesByFlag(0, true); SimpleSkillTreeDefinition[] bigTrees = database.GetTreesByNumericRange(0, 20f, 100f);

Runtime: SimpleSkillTreeTracker

SimpleSkillTreeTracker is a runtime state tracker that manages skill tree node unlocks, point spending, prerequisite validation, cascade resets, and serializable snapshots.

Setup

// Create a tracker from your tree database var tracker = new SimpleSkillTreeTracker(treeDatabase); // Initialize trees for tracking (must be called before unlock/query) tracker.InitializeTree("WARRIOR_COMBAT"); tracker.InitializeTree("MAGE_ARCANE");

Unlocking Nodes

// Check if a node can be unlocked (validates all prerequisites) bool canUnlock = tracker.CanUnlockNode( "WARRIOR_COMBAT", nodeId: 3, playerLevel: 10, availablePoints: 5 // pass -1 to skip point check ); // Unlock a node (does NOT deduct points -- your game manages point balance) bool unlocked = tracker.UnlockNode("WARRIOR_COMBAT", nodeId: 3, playerLevel: 10); // Check if a node is unlocked bool isUnlocked = tracker.IsNodeUnlocked("WARRIOR_COMBAT", nodeId: 3); // Check if a skill is unlocked in ANY initialized tree bool hasFireball = tracker.IsSkillUnlocked("FIREBALL");
Point management: UnlockNode tracks points spent internally (for requiredPointsInTree validation) but does not deduct from a player point balance. Your game code is responsible for checking and deducting available points before calling UnlockNode.

Queries

// Get total points spent in a tree int spent = tracker.GetPointsSpent("WARRIOR_COMBAT"); // Get points spent in a specific branch int fireSpent = tracker.GetPointsSpentInBranch("WARRIOR_COMBAT", "Fire"); // Get all unlocked node IDs int[] unlockedIds = tracker.GetUnlockedNodeIds("WARRIOR_COMBAT"); // Get all nodes that can currently be unlocked int[] available = tracker.GetAvailableNodeIds("WARRIOR_COMBAT", playerLevel: 10, availablePoints: 5); // Get all unlocked skill codes across ALL initialized trees string[] allUnlocked = tracker.GetAllUnlockedSkillCodes();

Reset

// Reset a single node (cascades to dependent child nodes) int refunded = tracker.ResetNode("WARRIOR_COMBAT", nodeId: 3); // Reset an entire tree int totalRefunded = tracker.ResetTree("WARRIOR_COMBAT"); // Clear all tracked state tracker.ClearAll();
Cascade reset: When you reset a node, all child nodes that depend on it (directly or transitively) are also reset. The returned value is the total points refunded across all reset nodes.

Events

tracker.OnNodeUnlocked += (treeCode, nodeId) => Debug.Log($"Unlocked node {nodeId} in {treeCode}"); tracker.OnNodeReset += (treeCode, nodeId) => Debug.Log($"Reset node {nodeId} in {treeCode}"); tracker.OnTreeReset += (treeCode) => Debug.Log($"Tree {treeCode} fully reset"); tracker.OnPointsChanged += (treeCode, newTotal) => Debug.Log($"Points spent in {treeCode}: {newTotal}");

Snapshots (Save/Load)

// Save current state SimpleSkillTreeTrackerSnapshot snapshot = tracker.CreateSnapshot(); string json = JsonUtility.ToJson(snapshot); // Load state var loaded = JsonUtility.FromJson<SimpleSkillTreeTrackerSnapshot>(json); tracker.RestoreFromSnapshot(loaded);