SetInkList Appears to be Incorrectly Implemented

Announcements, support questions, and discussion for the Dialogue System.
Post Reply
User avatar
ryanscottmurphy
Posts: 7
Joined: Mon Feb 26, 2024 10:22 am

SetInkList Appears to be Incorrectly Implemented

Post by ryanscottmurphy »

Hi Pixel Crushers/Tony,

I'm going a little bit deeper with my Ink/Dialogue System use in Ink and I noticed that the current behaviour attempts to set the List value using only a string object (which fails). I've investigated a little bit, and so far this is my current fix, which at least appears to set the InkList correctly.

DialogueSystemIntegration.cs

Code: Select all

public static void SetInkList(string variableName, string value)
{
    // This is good but doesn't account for adding/removing/replacing lists.
    Story story = instance.stories[0];
    string[] arr = value.Split(',');
    InkList newList = story.variablesState[variableName] as Ink.Runtime.InkList ?? new InkList();
    foreach (string a in arr)
    {
        string itemName = a.Trim();
        if (itemName.Trim().Contains('.'))
            newList.AddItem(new InkListItem(itemName));
        else
            newList.AddItem(new InkListItem(variableName, itemName));
    }
    
    if (m_instance != null) m_instance.SetInkVariableValue(variableName, newList);
}
I wanted to make a post and question some of my assumptions/understandings so far.

Firstly, am I correct that setting lists was implemented, but probably not working correctly? (So far, I think I am correct, but I could be missing something).

Is the intention/assumption of the DialogueSystemIntegration that all interactions in Ink should go through the DialogueSystemIntegration layer so that the Lua script is correctly notified or is this not necessary?

In DialogueSystemIntegration.cs, I've noticed that most Set/Get functions have the following loop:

Code: Select all

foreach (var story in stories)
I'm not really sure what the utility of having multiple stories in a single application is right now, but I'm wondering if you have an opinion about that. Is the assumption that separate stories would/should mirror each other's use of global variables, or at least not share names of global variables across stories?

My thought process is that SetInkList functionality should probably be replaced by Add, Subtract and Intersect behaviour as documented in the Ink.Runtime.InkList class, unless the intention is to interface directly with InkLists as needed. If so I'll probably write that for my own use and drop that here, but your insights are really appreciated so that I know that I'm going in the right direction.
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: SetInkList Appears to be Incorrectly Implemented

Post by Tony Li »

Hi,

Thanks for the detailed writeup. I'll take a look at this and get back to you.
User avatar
ryanscottmurphy
Posts: 7
Joined: Mon Feb 26, 2024 10:22 am

Re: SetInkList Appears to be Incorrectly Implemented

Post by ryanscottmurphy »

In the interest of sparing you some time, here is a solution I've made that inserts the Lists correctly, but I haven't got a clear enough understanding of the framework yet to know whether it's best to maintain the DialogueSystemIntegration layer, or whether I should just interface directly with Ink.

I assume that the value of putting it at the DialogueSystemIntegration layer is that I can add Lua functions that are usable from Dialogue System scripts.

Feel free to use this if you think it's on the right track, as it will save me patching it in for myself over and over with updates, though I suppose I can derive my own class over the top of yours if necessary:

Code: Select all

protected static InkList InkListFromCommaSeparatedString(string variableName, string value, Story story)
{
    string[] arr = value.Split(',');
    InkList list = new InkList(variableName, story);
    foreach (string a in arr)
    {
        string itemName = a.Trim();
        if (itemName.Trim().Contains('.'))
            list.AddItem(new InkListItem(itemName));
        else
            list.AddItem(new InkListItem(variableName, itemName));
    }

    return list;
}

public static void AddInkList(string variableName, string value)
{
    InkList newList = null;
    foreach (var story in instance.stories)
    {
        if (story.variablesState.GlobalVariableExistsWithName(variableName))
        {
            InkList newValues = InkListFromCommaSeparatedString(variableName, value, story);
            InkList currentList = story.variablesState[variableName] as Ink.Runtime.InkList;
            newList = currentList != null ? currentList.Union(newValues) : newValues;
        }
    }

    if (newList == null) return;
    if (m_instance != null) m_instance.SetInkVariableValue(variableName, newList);
}

public static void SubtractInkList(string variableName, string value)
{
    InkList newList = null;
    foreach (var story in instance.stories)
    {
        if (story.variablesState.GlobalVariableExistsWithName(variableName))
        {
            InkList values = InkListFromCommaSeparatedString(variableName, value, story);
            InkList currentList = story.variablesState[variableName] as Ink.Runtime.InkList;
            newList = currentList != null ? currentList.Without(values) : values;
        }
    }

    if (newList == null) return;
    if (m_instance != null) m_instance.SetInkVariableValue(variableName, newList);
}

public static void IntersectInkList(string variableName, string value)
{
    InkList newList = null;
    foreach (var story in instance.stories)
    {
        if (story.variablesState.GlobalVariableExistsWithName(variableName))
        {
            InkList values = InkListFromCommaSeparatedString(variableName, value, story);
            InkList currentList = story.variablesState[variableName] as Ink.Runtime.InkList;
            newList = currentList != null ? currentList.Intersect(values) : values;
        }
    }

    if (newList == null) return;
    if (m_instance != null) m_instance.SetInkVariableValue(variableName, newList);
}

public static void SetInkList(string variableName, string value)
{
    InkList newList = null;
    foreach (var story in instance.stories)
    {
        if (story.variablesState.GlobalVariableExistsWithName(variableName))
        {
            newList = InkListFromCommaSeparatedString(variableName, value, story);
        }
    }
    
    if (m_instance != null) m_instance.SetInkVariableValue(variableName, newList);
}
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: SetInkList Appears to be Incorrectly Implemented

Post by Tony Li »

Hi,

Thanks again for the code. I looked it over and added it to the integration. The RegisterLuaFunctions() method is now:

Code: Select all

        protected virtual void RegisterLuaFunctions()
        {
            if (m_registeredLuaFunctions) return;
            m_registeredLuaFunctions = true;
            Lua.RegisterFunction(nameof(SetInkBool), null, SymbolExtensions.GetMethodInfo(() => SetInkBool(string.Empty, false)));
            Lua.RegisterFunction(nameof(SetInkNumber), null, SymbolExtensions.GetMethodInfo(() => SetInkNumber(string.Empty, (double)0)));
            Lua.RegisterFunction(nameof(SetInkString), null, SymbolExtensions.GetMethodInfo(() => SetInkString(string.Empty, string.Empty)));
            Lua.RegisterFunction(nameof(SetInkList), null, SymbolExtensions.GetMethodInfo(() => SetInkList(string.Empty, string.Empty)));
            Lua.RegisterFunction(nameof(AddInkList), null, SymbolExtensions.GetMethodInfo(() => AddInkList(string.Empty, string.Empty)));
            Lua.RegisterFunction(nameof(SubtractInkList), null, SymbolExtensions.GetMethodInfo(() => SubtractInkList(string.Empty, string.Empty)));
            Lua.RegisterFunction(nameof(IntersectInkList), null, SymbolExtensions.GetMethodInfo(() => IntersectInkList(string.Empty, string.Empty)));
            Lua.RegisterFunction(nameof(GetInkBool), null, SymbolExtensions.GetMethodInfo(() => GetInkBool(string.Empty)));
            Lua.RegisterFunction(nameof(GetInkNumber), null, SymbolExtensions.GetMethodInfo(() => GetInkNumber(string.Empty)));
            Lua.RegisterFunction(nameof(GetInkString), null, SymbolExtensions.GetMethodInfo(() => GetInkString(string.Empty)));
            Lua.RegisterFunction(nameof(GetInkList), null, SymbolExtensions.GetMethodInfo(() => GetInkList(string.Empty)));
        }
and the functions will behave exactly as in your version, so when you update it should continue to work exactly the same.

Running Ink through the Dialogue System integration lets you tie into the Dialogue System's dialogue UI properly, specify different actors for different lines, run sequences, and receive the Dialogue System's special messages such as OnConversationStart and OnConversationEnd.

Most Ink + Dialogue System users run a single story, typically split across many files using INCLUDE directives. But some do use multiple separate stories, so we support both options.
User avatar
ryanscottmurphy
Posts: 7
Joined: Mon Feb 26, 2024 10:22 am

Re: SetInkList Appears to be Incorrectly Implemented

Post by ryanscottmurphy »

Running Ink through the Dialogue System integration lets you tie into the Dialogue System's dialogue UI properly, specify different actors for different lines, run sequences, and receive the Dialogue System's special messages such as OnConversationStart and OnConversationEnd.
Okay! Good, I didn't want to be adding code to the integration if it wasn't adding any value.
Most Ink + Dialogue System users run a single story, typically split across many files using INCLUDE directives. But some do use multiple separate stories, so we support both options.
I suspected this was the case! Thank you for clarifying. I'm not sure if it's preferable to look for the currently active story or if traversing all stories is best...

For now it works for me, so I'm satisfied, but if it can be improved I'm all about it.

I noticed that registering these Ink specific functions here doesn't appear to add them to the Lua Condition Wizard, is there somewhere I can look if I'm interested in adding that?

As an aside, is there a method for removing the Actions from the DialogueSystemTrigger or DialogueSystemInkTrigger? Once I add them, I can't seem to remove them without removing the whole component and remaking it.
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: SetInkList Appears to be Incorrectly Implemented

Post by Tony Li »

Hi,

I'll post the updated Ink Support package here later today. To make functions available to the Conditions and Script Lua wizards, they need to be added to a Custom Lua Function Info asset. The updated Ink Support package's Custom Lua Function Info asset has all of the Ink-related functions in it.

For the Dialogue System Trigger, you can generally either click an 'x' to remove the action (such as with Bark or Start Conversation) or just clear the contents of the action (such as the OnExecute() UnityEvent). Then next time to return to the Dialogue System Trigger in the inspector, that action will no longer be shown.
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: SetInkList Appears to be Incorrectly Implemented

Post by Tony Li »

Here's the updated Ink Support package:

DS_InkSupport_2024-02-28.unitypackage
User avatar
ryanscottmurphy
Posts: 7
Joined: Mon Feb 26, 2024 10:22 am

Re: SetInkList Appears to be Incorrectly Implemented

Post by ryanscottmurphy »

You're so incredibly prompt and responsive Tony, thanks so much for your help!
User avatar
Tony Li
Posts: 22110
Joined: Thu Jul 18, 2013 1:27 pm

Re: SetInkList Appears to be Incorrectly Implemented

Post by Tony Li »

Thanks! Glad to help!
Post Reply