Integrating Gameplay Actions
Action nodes connect a graph to your own gameplay code through stable action IDs. The graph describes when an action runs; your handler owns the game-specific behavior.
1. Create an action definition
- Open Tools > Beka Forge > Dialogue Graph System > Open Editor, then open the Definitions workspace and its Actions section.
- Select the + button to create an action asset. You can also use Unity's Create > Beka Forge > Dialogue Graph System > Actions > Action menu.
- Set a stable Action ID, for example
UnlockGate, and a readable display name and description. - Set Default Payload JSON if the handler needs data. Keep it valid JSON. Choose Wait For Completion if the graph should wait for the handler coroutine; configure a default delay only when that delay is intentional.
Use the exact same ID in the graph node and the handler's CanHandle method. An action definition is data: it does not create the gameplay effect by itself.
2. Place an action in the graph
- Open a graph and create an Action node from the graph context menu.
- On the Action card in the graph, set Action ID and assign the definition in Registered Action. Expand Payload & Timing to review the payload and wait/delay fields.
- Connect the node into the intended route. Save the graph and review its links in the active Graphs workspace.
Try the Action example: change Action ID, expand Payload & Timing, edit the raw Payload JSON, and toggle Wait For Completion. The preview shows authored values only; it does not invoke a handler or animate a gate.
Expected result: the graph contains a reachable action node with an assigned definition. The action will only do work at runtime if an appropriate handler is registered on the scene's action set.
3. Implement an explicit handler
Implement IActionHandler on a scene MonoBehaviour. Register that component in a ConversationActionSet's handlers list; handlers are not automatically discovered.
using System.Collections;
using DialogSystem.Runtime.Interfaces;
using UnityEngine;
public sealed class UnlockGateHandler : MonoBehaviour, IActionHandler
{
[SerializeField] private Animator gateAnimator;
public bool CanHandle(string actionId) => actionId == "UnlockGate";
public IEnumerator Handle(string actionId, string payloadJson)
{
if (gateAnimator != null)
gateAnimator.SetTrigger("Unlock");
// Keep the coroutine alive here if dialogue must wait for your animation.
yield return null;
}
}
CanHandle selects the action IDs this component accepts. Handle receives the ID and payload JSON. Parse payloads defensively and keep the ID comparison consistent with the definition and graph node.
4. Register the action set
Add a DialogActionRunner to the manager GameObject or assign it in the manager component. In the runner, use its global action set or add a dialogue-specific ConversationActionSet. For a dialogue-specific mapping, make its dialogueKey match the manager's dialogID and add the handler component to that set's handlers list. The runner can use its configured global fallback when enabled.
For a one-off scene action, use the supplied DGS sample as a reference for its action runner and handler wiring. Do not assume that adding a component to the scene automatically registers it.
UnityEvent alternative
For a simple serialized callback, add an ActionBinding to the selected action set, enter the matching actionId, and wire its On Invoke (string payload) UnityEvent. This binding belongs to the action set, not the DialogActionSO definition. Use an IActionHandler for coroutine timing, payload parsing, or reusable logic that should be tested in code. Keep critical state changes in your game systems rather than putting them in dialogue UI code.
Troubleshooting
- No effect occurs: compare the action ID in the definition, graph node, and handler; verify the handler is listed in the selected action set.
- The dialogue does not wait: check Wait For Completion and ensure the handler returns a coroutine that yields for the work you need to finish.
- Payload is empty or invalid: verify the node payload and default payload are valid JSON and that the handler reads the same shape.
- Action works for one dialogue only: check the dialogue-specific key against the manager's registered
dialogID, or configure the intended global set/fallback.