Storyteller 2019.2
Storyteller Scripting API Documentation (BETA)
Extending storyteller and accessing storyteller data is made easy using game bridge and following examples you will find in the Scripting API Documentation.

Before you continue, please download the Game Bridge extension for Storyteller here on Github.


The first thing that you need to do to access storyteller is to access your story project and then access your scenes. This is a simple process. There are three different ways of access your story project data. Accessing Storyteller data using Currentstory.ActiveStory means that you accessing your story from code thay will not be in game. However if you wish to access storyteller data and make use of it in game then please look at the second example.
using UnityEngine;
using DaiMangou.Storyteller;
using DaiMangou.BridgedData;
public class StoryAndSceneAccessFromEditor
{
// Run this method however you choose
public void EditorAccessMethod()
{
// first we must access our story project. if we want to access the currentstory currently running in storyteller we can simply say
var myStory = CurrentStory.ActiveStory;
// we can then access the currently running scene
var myScene = myStory.Scenes[CurrentStory.ActiveScene]; // CurrentStory.ActiveScene being the index of the active scene
// from this point we have access to all of our scen data
foreach (var character in myScene.Characters)
{
Debug .Log(character.name);
}
foreach (var environment in myScene.Environments)
{
Debug .Log(environment.name);
}
foreach (var node in myScene.NodeElements)
{
Debug .Log(node.GetType());
}
Debug .Log(myScene.Duration);
Debug .Log(myScene.Overview);
Debug .Log(myScene.Theme);
// etc
// foreach (var node in myScene.)
}
}

This is called a SceneData Asset and it contains all the scene data of whichever Storyteller Scen you send to it and can be used in game. You can create a SceneData Asset by going to

Assets > Create>GameBridge > SceneData


Here you see two SceneData Assets . one for SceneData to be used in a DatingSim and the other to be uesd in dynamic NPC dialogue SceneData Assets
Please watch this video to see how these SceneData Assets are used.

Inside of a SceneData Asset you have direct access to each character and their data for each chain of events in the scene. There are three main lists of data in each SceneData Asset. FullCharacterDialogueSet, ActiveCharacterDialogueSet, Characters

FullCharacterDialogueSet contains all Actions,Dialogue,Routes,Links and End ndoe data of your scene. ActiveCharacterDialogueSet contains the current requested chain of events of a scene at runtime. Characters contain all of the characters in your current scene.

Each character contains a list of all their Actions,Dialogue,Routes,Links and End ndoe data. As you see in your Storyteller Timeline, only dialogue and actions of the active route path are displayed. In the characters list of Actions,Dialogue,Routes,Links and End ndoe data only the active route path are able to be processed by the Dialouger Component and the Character Component these pieces of data are flagged false by the "pass" boolean.

You will now be shows how the Character Component and Dialoguer Component generate the ActiveCharacterDialogueSet.

In our DialoguerComponent , it is assued that you wish to use all characters dialogue as shown in the Storyteller Timeline. So we just take all the data that is not set to pass from inside the FullCharacterDialogueData wt and we send them to the ActiveCharacterDialogueSet.

void GenerateActiveDialogueSet()
{
//region here we will populate the ActiveChracterDalogueSet at runtime, unlike the FullCharacterDialogueSet list, this list will have all nodes ordered correctly for execution at runtime
// firstly make ActiveCharacterDialogueSet a new list
sceneData.ActiveCharacterDialogueSet = new List();
for (var i = 0; i < sceneData.FullCharacterDialogueSet.Count; i++)
{
var data = sceneData.FullCharacterDialogueSet[i];
// each NodeData in the FullCharacterDialogueSet already has their pass values set when the data was first pushed to the Dialoguers SceneData scriptableObject so we just check the values
if (!data.Pass)
{
// we want to ignore all character and environment nodes
if (data.type != typeof(CharacterNodeData) && data.type != typeof(EnvironmentNodeData))
{
sceneData.ActiveCharacterDialogueSet.Add(data);
}
}
}
}

You may also select any character or group of characters and put their Action,Dialogue,Link,Routeand End data together and build dialogue or interactions that way. This is what the Character Component does. it allows for any two or more characters to spwan dialogue and interact dynamically. Making it possible for completely unplanned interactions to happen.

// here we are basically saying that we want therese three characters to interact with each other at this time. This can be done dynamically as you see in theCharacter.cs code at line 105
var combinedData = sceneData.Characters[0].NodeDataInMyChain.Concat(sceneData.Characters[3].NodeDataInMyChain)
.Concat(sceneData.Characters[5].NodeDataInMyChain).ToList();
// countlist = new List();
// here we will populate the ActiveChracterDalogueSet at runtime, unlike the NodeDataInMyChain list, this list will have all nodes ordered correctly for execution at runtime
// firstly make ActiveCharacterDialogueSet a new list
sceneData.ActiveCharacterDialogueSet = new List();
for ( var i = 0; i < combi.Count; i++)
{
var data = combi[i];
// each n=NodeData in the combi already has their has value set when the data was first pushed to the Dialoguers DialogueData scriptableObject so we just check the values
if (!data.Pass)
{
// countlist.Add(i);
// we want to ignore all character and environment nodes
if (data.type != typeof( CharacterNodeData) && data.type != typeof( EnvironmentNodeData))
{
sceneData.ActiveCharacterDialogueSet.Add(data);
}
}
}

Start Time

Start time is the time which Dialogue,Actions,routes, links and end nodes data is processed in game. And then we ensure that the each node has a propper start time.
The start time is key in ensureing that all out dialogue is triggered in order.
// you may assign any number of characters to this character list.
var Characters = new List<CharacterNodeData>();
//e.g
Characters.Add(sceneData.Characters[0]);
Characters.Add(sceneData.Characters[3]);
Characters.Add(sceneData.Characters[5]);
// or you may use the entire preexisting list of characters list sceneData.Characters
// here we will begin the process of setting times on all other nodes. Do not break this function.
foreach (var character in Characters)
{
// we will start from the end of the nodeData list and assign start times and delay times in reverse.
for (int i = character.NodeDataInMyChain.Count - 1; i >= 0; i--)
{
// if the nodeData is not set to pass then lets process it.
if (!character.NodeDataInMyChain[i].Pass)
{
if (character.NodeDataInMyChain[i].type == typeof(RouteNodeData))
{
var route = (RouteNodeData)character.NodeDataInMyChain[i];
if (!route.OverrideStartTime)
route.StartTime = route.DataIconnectedTo[route.RouteID].StartTime - 0.0001f;
}
if (character.NodeDataInMyChain[i].type == typeof(LinkNoLinkNodeDatadeData))
{
var link = (LinkNodeData)character.NodeDataInMyChain[i];
if (!link.OverrideStartTime)
link.StartTime = link.DataIconnectedTo[0].StartTime - 0.0001f;
}
// end nodes are connected to nothing , so we must look at the entire list again and find the node data with the largest start time in the current chain and use that value as the // an nodes start time.
if (character.NodeDataInMyChain[i].type == typeof(EndNodeData))
{
var end = (EndNodeData)character.NodeDataInMyChain[i];
var templist = new List();
foreach (var n in character.NodeDataInMyChain)
{
if (!n.Pass)
{
templist.Add(n);
}
}
end.StartTime = templist.Max(s => s.StartTime);
}
}
}
}
//finally lets sort the ActiveCharacterDialogueSet by start time
sceneData.ActiveCharacterDialogueSet = sceneData.ActiveCharacterDialogueSet.OrderBy(t => t.StartTime).ToList();

At this point you already know how to access your story and scene data. You know how to put character data into the ActiveCharacterDialogueSet and Sort the Start times.

Okay, so how do we show data from nodes you selected in storyteller ; inside the inspector if the Dialoguer or Character components ? Simple. We look at what the selected storyteller node is and then we check to see if its ID and then check to see if its ID xists in out ActiveCharacterDialogueData list. If it dows . we display its data in the inspector. An exampe of tis is found in the Character.cs script at line 353 to line 363 All this is already scripted and handled for you.