Importing articy draft strips

Announcements, support questions, and discussion for the Dialogue System.
User avatar
Tony Li
Posts: 22143
Joined: Thu Jul 18, 2013 1:27 pm

Re: Importing articy draft strips

Post by Tony Li »

Good catch! Make a subclass of DialogueSystemSaver, and use it in place of the original DialogueSystemSaver. In ApplyData(), call ArticyTools.InitializeLuaSubtables():

DialogueSystemSaverWithArticy.cs

Code: Select all

namespace PixelCrushers.DialogueSystem
{
    public class DialogueSystemSaverWithArticy : DialogueSystemSaver
    {
        public override void ApplyData(string data)
        {
            base.ApplyData(data);
            PixelCrushers.DialogueSystem.Articy.ArticyTools.InitializeLuaSubtables();
        }
    }
}
Raidenthequick
Posts: 34
Joined: Mon Jul 02, 2018 5:00 pm

Re: Importing articy draft strips

Post by Raidenthequick »

That worked! Thanks!

The only thing now about it is that InitializeSubtables() appears to throw an error every time it's called. The exception message is:

Code: Select all

"Lookup of field 'DialogueSystem' in the table element failed because the table element itself isn't in the table."
When I inspect the code, it seems to be setting the entire state of all my Variables and Actors and perhaps Items too. The only thing peculiar about them that I could find is all the AlternatePortraits sets look like this:

Code: Select all

AlternatePortraits=PixelCrushers.DialogueSystem.LuaTableWrapper
I suspect these two are related? But not certain. You've already been very helpful but any assistance on this would be very appreciated as well. Thank you again!
User avatar
Tony Li
Posts: 22143
Joined: Thu Jul 18, 2013 1:27 pm

Re: Importing articy draft strips

Post by Tony Li »

Hi,

Does your articy project have a property named "DialogueSystem"?

The DialogueSystemSaver's ApplyData() method will reset the Actor[], Item[] and Variable[] tables. But ArticyTools.InitializeLuaSubtables() method shouldn't set them in their entirety. InitializeLuaSubtables() should only create subtables. If you temporarily set the Dialogue Manager's Other Settings > Debug Level to Info, it should log lines similar to:

Code: Select all

Dialogue System: Lua( Actor["Name"].MySubtable = { 1, 2, 3 } )
Debug Level = Info may also give you context about when it throws the exception.

BTW, I think AlternatePortraits should be fine. That means it's a subtable.

Please feel free to send a reproduction project to tony (at) pixelcrushers.com. I'll be happy to take a look.
Raidenthequick
Posts: 34
Joined: Mon Jul 02, 2018 5:00 pm

Re: Importing articy draft strips

Post by Raidenthequick »

I ended up digging into this more. I was right that lua doesn't like "PixelCrushers.DialogueSystem.LuaTableWrapper", as this is a C# typename that doesn't belong in lua.

I traced it down to GetFieldValueString, so I added a type handler for a table WITHIN a table.

Code: Select all

        private static string GetFieldValueString(object o)
        {
            if (o == null)
            {
                return "nil";
            }
            else
            {
                System.Type type = o.GetType();
                if (type == typeof(string))
                {
                    return string.Format("\"{0}\"", new System.Object[] { DialogueLua.DoubleQuotesToSingle(o.ToString().Replace("\n", "\\n")) });
                }
                else if (type == typeof(bool))
                {
                    return o.ToString().ToLower();
                }
                else if (type == typeof(float) || type == typeof(double))
                {
                    return ((float)o).ToString(System.Globalization.CultureInfo.InvariantCulture);
                }
                else if (type == typeof(LuaTableWrapper))
                {
                    StringBuilder sb = new StringBuilder();
                    AppendFields(sb, (LuaTableWrapper)o);
                    return sb.ToString();
                }
                else
                {
                    return o.ToString();
                }
            }
        }
I'll optimize it for GC better (creating a new StringBuilder every time could add up), but this seems to be working for me.
User avatar
Tony Li
Posts: 22143
Joined: Thu Jul 18, 2013 1:27 pm

Re: Importing articy draft strips

Post by Tony Li »

Thanks. I'll take a look at this and implement it or a similar fix in the importer.
_marc
Posts: 69
Joined: Mon Nov 05, 2018 5:44 am

Re: Importing articy draft strips

Post by _marc »

Tony Li wrote: Wed Apr 15, 2020 8:26 am Good catch! Make a subclass of DialogueSystemSaver, and use it in place of the original DialogueSystemSaver. In ApplyData(), call ArticyTools.InitializeLuaSubtables():

DialogueSystemSaverWithArticy.cs

Code: Select all

namespace PixelCrushers.DialogueSystem
{
    public class DialogueSystemSaverWithArticy : DialogueSystemSaver
    {
        public override void ApplyData(string data)
        {
            base.ApplyData(data);
            PixelCrushers.DialogueSystem.Articy.ArticyTools.InitializeLuaSubtables();
        }
    }
}
Hi Tony,
I was experiencing the same issue, but with the PersistentDataManager instead of the complete Save System. The situation is the same: I start from a game launcher (main menu), then I load a saved game.
Based on your solution, I tried to call InitializeLuaSubtables() just after the line PersistentDataManager.ApplySaveData. Problem solved, now I can get the lua subtable.
But... :(
When I iterate over the stripTable, each element now has only one Key/Value pair in its table (so there is no Technical Name, which is what I'm looking for here)!

Code: Select all

    public static string[] GetStripElementsIDs(LuaTableWrapper stripTable)
    {
        string[] elementsIDs = new string[stripTable.count];
        int i = 0;
        foreach (LuaTableWrapper element in stripTable.Values)
        {
            elementsIDs[i] = element[DialogueLua.StringToTableIndex(MyToolbox.Lua.ArticyFields.techName)].ToString(); // <-- Null Reference Exception
            i++;
        }
        return elementsIDs;
    }
The only existing field is the one explicitly saved with "PersistentDataManager.GetCustomSaveData" (I don't want to save the other fields).
When I don't load the lua environment (that is, when I start directly from the Unity editor), the same LuaTableWrapper element shows almost 20 key/value pairs, and the field I'm looking for exists, and everything works fine.

So, to summarize:
case A (no loading)
-> InitializeLuaSubtables
-> iterate over the strip -> found 3 elements with almost their 20 fields

case B (starting from main menu, loading)
-> InitializeLuaSubtables
-> load lua environment
-> InitializeLuaSubtables
-> iterate over the strip -> found 3 elements with only 1 field, the one previously saved withPersistentDataManager.GetCustomSaveData. The other fields seem to be gone.

Any idea of what's happening?
User avatar
Tony Li
Posts: 22143
Joined: Thu Jul 18, 2013 1:27 pm

Re: Importing articy draft strips

Post by Tony Li »

Hi,

If you're only saving one field in GetCustomSaveData, won't it only restore one field? Can you save the entire table in your GetCustomSaveData?

The catch with InitializeLuaSubtables is that it clears the original runtime value of the compressed field that was made by the importer, so calling it again won't add the missing fields.
_marc
Posts: 69
Joined: Mon Nov 05, 2018 5:44 am

Re: Importing articy draft strips

Post by _marc »

In fact, it seems that the InitializeLuaSubtable has nothing to do with my problem (I should have done a new topic!), because when I bypass it, the original fields are still missing after loading.
I thought the GetCustomSaveData was a way to optimize the amount of data recorded, avoiding the use of PersistentDataManager.InludeAllItemData, and allowing to restore only specific, immutable fields.

What I don't understand and what looks weird to me, with an Item containing many fields: if with GetCustomSaveData I save one field, all the other fields are lost after loading. But if I save no fields at all, they're all preserved.
Shouldn't the saved data only restore values in existing fields rather than creating new fresh fields?

In my case, saving all fields for Items would be a waste of resources because 90% of these are immutable, and it would add at least thousands of useless entries in my .xml document, which I try to keep as readable as possible. The GetCustomSaveData delegate is really a great idea, I think it's a shame for me not to use it :?

Do you think you could add an option (in the importer, maybe?) allowing to restore field values found in the custom saved data without clearing existing fields?
User avatar
Tony Li
Posts: 22143
Joined: Thu Jul 18, 2013 1:27 pm

Re: Importing articy draft strips

Post by Tony Li »

Hi,

It sounds like your GetCustomSaveData method is overwriting the entire Item element. GetCustomSaveData should generate Lua code that will restore the data that you need to restore. For example, this code:

Code: Select all

Item["MyItem"] = { FieldX = "xyz"; }
will configure Item["MyItem"] with only one field (FieldX).

Instead, use this:

Code: Select all

Item["MyItem"].FieldX = "xyz"
It will set the FieldX field of Item["MyItem"] without overwriting its entire table.
_marc
Posts: 69
Joined: Mon Nov 05, 2018 5:44 am

Re: Importing articy draft strips

Post by _marc »

You're completely right, there was a nice mistake in my GetCustomSaveData function! I was actually creating a new table instead of just filling existing values. The problem was quite simple, but I was looking in the wrong direction :|
Thanks a lot for your precious help, Tony, again!
Post Reply