Skip to main content

CommandGraph

The node-based visual scripting system that drives NPC and event behaviour — dialogs, branches, item/money grants, warps, battles, quests and more. Each interactable actor owns an ActorCommandGraph; the graph is authored in the editor and executed as a coroutine at runtime.

command graph

A graph is an asset. Nothing in this path is compiled, which is why it works the same in the DLL tiers where you cannot open the source.

Namespace: OpenMon.MCE.Actors.CommandGraph

Authored in the editor, run at runtime

You normally build command graphs in the visual editor (see the CommandGraph guide), not from C#. The runtime surface below is what you touch when you extend the system with a custom node or run a graph programmatically. The node types themselves (ShowDialog, GivePlayerItem, TeleportPlayer, …) are authored assets — their fields are inspector-serialized, not a code-facing API.

ActorCommandGraph​

The container for one actor's graph.

[Serializable]
public class ActorCommandGraph
{
public bool IsRunning { get; }

[SerializeReference] public CommandNode RootNode;
[SerializeReference] public List<CommandNode> Nodes;

public bool IsGraphEmpty { get; }

public IEnumerator Run(CommandParameterData parameterData,
Action<bool> onLoopRunningUpdatedCallback = null);

public CommandNode CreateNode(Type type, Vector2 position = default);
public void DeleteNode(CommandNode node);
public void ConnectNodes(CommandNode parent, CommandNode child, int parentIndex);
public void RemoveConnection(CommandNode parent, CommandNode child, int parentIndex);
public List<CommandNode> GetChildren(CommandNode node);
}

IsRunning​

Whether this graph is currently executing.

Type: bool (read-only)

RootNode​

The entry CommandNode (a RootNode) execution starts from. Serialized by reference so polymorphic node types round-trip.

Type: CommandNode

Nodes​

Every node in the graph, including nodes not reachable from RootNode (kept so the editor can persist orphaned/disconnected nodes).

Type: List<CommandNode>

IsGraphEmpty​

true when there is no root node or the root has no children.

Type: bool (read-only)

Run(CommandParameterData parameterData, Action<bool> onLoopRunningUpdatedCallback = null)​

Execute the graph. Sets IsRunning, then runs RootNode.RunCommandAndContinue, threading a CommandParameterData context through every node.

Returns: IEnumerator — yield it from a coroutine.

CreateNode(Type type, Vector2 position = default) / DeleteNode / ConnectNodes / RemoveConnection​

Editor-facing graph mutation: instantiate a node of a given CommandNode subclass, remove it, and wire/unwire parent→child connections by output-port index.

CommandNode​

The abstract base every node type derives from.

[Serializable]
public abstract class CommandNode : MonsterDatabaseData<CommandNode>
{
public bool IsRunning { get; }
public string name;
public string GUID;
public Vector2 Position;
public Action OnPortsUpdated;

public virtual IEnumerator RunCommandAndContinue(CommandParameterData parameterData);

protected abstract IEnumerator Run(CommandParameterData parameterData,
Action<CommandParameterData> callback);

public abstract List<string> GetInputPorts();
public abstract List<string> GetOutputPorts();
public abstract void AddChild(CommandNode child, int index);
public abstract void RemoveChild(CommandNode child, int index);
public abstract List<CommandNode> GetChildren();
public abstract List<CommandNode> GetIndexedChildren();
}

RunCommandAndContinue(CommandParameterData parameterData)​

Runs this node (via the abstract Run) and then continues to its children. Handles loop gating when the graph runs on a loop.

Run(CommandParameterData parameterData, Action<CommandParameterData> callback)​

protected abstract — the actual work of a node. Override this in a custom node. Call callback with the (possibly modified) parameter data when done.

GetInputPorts() / GetOutputPorts()​

The named input/output ports the node exposes to the editor graph. A linear node has a single unnamed port on each side; a branch node exposes one output per branch.

Returns: List<string>.

SingleExecutionPathCommandNode​

Most nodes derive from SingleExecutionPathCommandNode, a CommandNode with exactly one output port (NextCommand). Branch nodes (If…, Switch…, While…) instead expose multiple output ports.

public abstract class SingleExecutionPathCommandNode : CommandNode
{
public CommandNode NextCommand;
// GetOutputPorts() => one unnamed port; AddChild sets NextCommand.
}

CommandParameterData​

The execution context threaded through every node during a run — the surface a custom node reads from and writes to.

public class CommandParameterData
{
public ActorCommandGraph Graph;
public GameObject Owner;
public Actor Actor;
public MCECharacterController.Direction PlayerDirection;
public PlayerCharacter PlayerCharacter;
public GlobalGameData GlobalGameData;
public MCESettings MCESettings;
public MonsterDatabaseInstance MonsterDatabase;
public IBattleLauncher BattleLauncher;
public ILocalizer Localizer;
public IConfigurationManager ConfigurationManager;
public IInputManager InputManager;
public PlayerTeleporter Teleporter;
public SavegameManager SavegameManager;
public MapSceneLauncher MapSceneLauncher;
public TimeManager TimeManager;
public QuestManager QuestManager;
public TradeManager TradeManager;
public bool UsingMove;
public MonsterInstance MoveUser;
public Move Move;
public bool IsRunningOnLoop;
public ICommandParameter[] ExtraParams;
public Action<CommandCallbackParams> Callback;
}

Built-in node categories​

Nodes are grouped by folder under Actors/CommandGraph/. Representative types:

CategoryExample nodes
DialogsShowDialog, ShowChoiceDialog, ShowSignDialog, NextDialog
ItemsGivePlayerItem, GivePlayerMoney, IfPlayerHasItem, ChooseItemDialog
MonstersGiveMonsters, HealPlayerRoster, ChooseMonsterDialog, ChangeMonsterNickname
BattlesSingleWildFight, SingleTrainerFight, DoubleWildFight, StartTowerRun
BadgesGiveBadge, IfPlayerHasBadge
DexGiveDex, RegisterMonsterAsSeen, IfDexIsComplete
QuestsStartQuest, CompleteQuest, ProgressQuestObjective, IfCompletedQuest
VariablesSetBoolVariable, SetIntVariable, IfBool, IfCondition, WhileBool
UtilsTeleportPlayer, WaitTime, AutoSaveIfEnabled, SwitchTimeOfDay
AnimationsMove, Look, LookAtPlayer, WalkToPlayer, FadeScreenToBlack
Shops / TradeBuyInShop, SellInShop, TradeSelectedMonster

Writing a custom node​

using System;
using System.Collections;
using System.Collections.Generic;
using OpenMon.MCE.Actors.CommandGraph;

namespace MyGame.Events
{
[Serializable]
public class LogStepsTaken : SingleExecutionPathCommandNode
{
protected override IEnumerator Run(CommandParameterData parameterData,
Action<CommandParameterData> callback)
{
// Read from the shared context threaded through the graph.
uint steps = parameterData.GlobalGameData.StepsTaken;
UnityEngine.Debug.Log($"Player has taken {steps} steps.");

callback(parameterData);
yield break;
}
}
}