dialogic-godot / documentation

📖 The documentation for the Dialogic Godot plugin.
http://docs.dialogic.pro
16 stars 12 forks source link

Troubles with Dictionary argument inside of CallEvent #51

Closed 0-Vanes-0 closed 4 months ago

0-Vanes-0 commented 4 months ago

I created CallEvent in Timeline resource and set a function of some singleton script. My function receives a Dictionary argument so I added an argument of type Expression (Any)

image

When I launch my timeline - this CallEvent works as desired. But if I restart Godot and check this timeline in Visual Editor - it is empty. Output prints error: res://addons/dialogic/Editor/Events/Fields/array_part.gd:55 - Invalid call. Nonexistent function 'trim_prefix' in base 'Dictionary'.

image

Although in Text Editor everything is good: do Global.set_actor_state("Player", "idle", {"animation": "idle"}) The issue isn't critical cuz code works but it is visual bug which is undesirable.

0-Vanes-0 commented 4 months ago

Tried to change "array_part.gd" by myself. I found out that there's "field_dictionary.tscn" already.

# _ready()
},{
    'label': 'Dictionary',
    'icon': ["Dictionary", "EditorIcons"],
    'value': TYPE_DICTIONARY
},{
# set_value()
TYPE_DICTIONARY:
    value_field.set_value(value)
# _on_type_changed()
TYPE_DICTIONARY:
    current_value = DialogicUtil.var_to_dict(current_value)
    set_value(current_value)
# change_field_type()
TYPE_DICTIONARY:
    value_field = load("res://addons/dialogic/Editor/Events/Fields/field_dictionary.tscn").instantiate()
    value_field.value_changed.connect(_on_dictionary_changed)
func _on_dictionary_changed(prop: String, value: Dictionary) -> void:
    current_value = value
    value_changed.emit()

Here's static function in DialogicUtil:

static func var_to_dict(value: Variant) -> Dictionary:
    var dictionary := {}

    if typeof(value) == TYPE_DICTIONARY:
        dictionary = value
    elif typeof(value) == TYPE_STRING:
        if value.begins_with('{'):
            var result = JSON.parse_string(value)
            if result != null:
                dictionary = result as Dictionary

    return dictionary

After restarting both Godot and Dialogic I managed to reach this:

image

But! Every time I edit this dict field - everything breaks and if we look at Text Editor, the CallEvent is written like this:

do Global.set_actor_state("Player", "idle", {
"animation": "idle"
})

It doesn't wanna do it in one line ( Ñ‚ . Ñ‚) Furthermore, it makes adding dict in Visual Editor currently impossible.

image after refresh: image

Jowan-Spooner commented 4 months ago

Interesting. I can try to look into this later this week.

0-Vanes-0 commented 4 months ago

I suppose I found the "place". Line 84 of event_call.gd:

image

The thing is that GlobalScope's function var_to_str() converts Dictionary to String with adding \n symbols. Example:

    var dict := { "a": 10, "b": 20 }
    var text := var_to_str(dict)
    print(text)

    text = text.replace("\n", "")

    print(text)

image

After discovering that I did this: image

aaand it is finally fixed! After restart and switching editor several times nothing breaks! However, if we add more key-value pairs - our dictionary has comma signs "," between pairs and they are recognized as separations of arguments, not as separations of dictionary's pairs. E.g. I write do Global.set_actor_state("Player", "idle", {"animation":"idle","type":"some_type"}) and in Visual Editor it becomes ugly:

image

So, next step: recognizing comma signs of Dictionary ":D

0-Vanes-0 commented 4 months ago

Issue resolved (I believe so). With some help from ChatGPT I fixed behavior of from_text() function:

image

I just decided to replace "," to ";" if "," isn't between [ ] or { } and then I split the text by ";"

# DialogicUtil.gd

## Splits arguments (represented as [param string]) separated for comma "," signs.
## The function takes into account if [param string] contains Array or Dictionary inside.
static func split_arguments(string: String) -> PackedStringArray:
    var brace_depth := 0
    var bracket_depth := 0

    for i in string.length():
        if string[i] == "{":
            brace_depth += 1
        elif string[i] == "}":
            brace_depth -= 1
        elif string[i] == "[":
            bracket_depth += 1
        elif string[i] == "]":
            bracket_depth -= 1
        elif string[i] == "," and brace_depth == 0 and bracket_depth == 0:
            string[i] = ";"

    var splitted := string.split(";")
    for i in splitted.size():
        splitted[i] = splitted[i].strip_edges()

    return splitted

Switching between editor's modes: image image

🥳 🤘

Might be it needs some testing cuz the dictionary will contain numbers, booleans etc. as Strings but it's not a big deal. So, should I do pull request?..