-
Notifications
You must be signed in to change notification settings - Fork 3
Support function calls from text #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Hi, thanks for submitting this PR - great idea, I really like it! I'm currently on holiday ATM but will have a look in detail as soon as I'm back :) |
|
Enjoy the holidays! Once you'll be back, if you deem the idea worthy, I'll be available to work on it following your directions, this was just a raw draft to present the idea |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cheers, I've had a look this morning and firstly, I just wanna say again - great idea! I like the convention you've chosen: Hello {{expression}}, how're you?
I have a couple of ideas which would be good to get your thoughts on too!
I wonder if we should move this processing into: addons/parley/models/dialogue_sequence_ast.gd and resolve the defined function calls within the . This is where the current processing happens so it would be good to keep all that together (this also has a load of tests that we can also extend for this use-case). Also, as this new feature is quite low level, users would then have the flexibility to use those APIs to process Dialogue Sequences with their own custom dialogue containers.next() function so the returned nodes are always fully resolved
For something similar a while back, I was looking into Godot Expressions. I reckon this could provide us with some out of the box functionality so we don't have to write the function parse/call code ourselves. This would also provide some extra flexibility in that it's not restricted to only function calls but in theory, any valid expression. E.g. we can use provided arguments to the processing such as ctx (and others in the future).
Let me know what you think and happy to discuss!
|
On a side note, I'm currently implementing translation support which is likely to be touching similar parts of the codebase so we may need to coordinate a bit. Nothing to worry about ATM, just thought I'd mention it as a heads up :) |
|
I agree with you that Godot expressions are a way better approach to this task, I've tested them and they work well for this use case. Let's call this new node "rich_dialogue", it would:
What do you think? |
|
Awesome stuff! :)
That's a really good point about the potential breaking change! That's a cool idea about the new rich node as well - I like the separation to increase stability/avoid breaking changes. I think my only concern about having an extra node type is that it could increase the complexity for both the user (and us) as they would have more to think about in terms of what nodes to add and a dialogue sequence would become cluttered with lots of different node types! For example, if we introduce rich_dialogues we'd probably want to introduce rich_dialogue_option nodes as well! I wonder if it would be simpler and easier for the user for us to stick with one type of node but we extend the existing functionality of the dialogue and dialogue_option nodes in a defensive manner to avoid the breaking changes and stability concerns you raised? For example, with this approach, we could make this post-processing configurable in parley settings or per-node options that are (in this version of Parley) both opt-in. This way, users can still use existing nodes but can optionally add in the extra processing if they'd like to. In subsequent major versions of Parley, we could then turn them on by default and have this functionality out of the box. wdyt? |
|
I've come back to work on this issue with some news:
I find this approach easy to code and I've already tested it, working without issues. I like the idea of adding per-node options, leading to a more granular control but I have no idea on how to implement this approach in the current code-base, is there some code that I can extend?
I've implemented text parsing but
Character name parsing is proving difficult with the current approach since we move around an object with id and name, parsing it would mean saving the new parsed name in storage, rendering the functionality useless and broken. Do you have any suggestions with character name parsing and per-node options? |
|
Ah awesome stuff, sounds like great progress so far! 🚀
At the moment, your best starting point is to look at extending the following files (and maybe start with a Checkbox Button):
Once things are developed a bit further, we'll need to extend some other files but these are a good starting point :) I'll try and write up a proper contributing guide tomorrow evening - let me know if that helps or you have any further questions in the meantime!
Good question! I think I see what you mean yeah as I may have run into similar issues when working on adding translation support last week. Just so I fully understand your question, do you have some example code I can take a look at? |
…tings to enable global rich text parsing
428c8d9 to
26d734e
Compare
|
I'm now experimenting on the granular render (per node) and I've found some issues to discuss: Having global settings + granular option on every node can be implemented but the logic to be applied needs to be discussed. I'm just writing the first two ideas that came to mind but there are more complex solutions that could be chosen. Global setting overwrites granular access
Pros
Cons
Granular setting decidesIn case of conflict (Global ON, local OFF) the local settings is chosen, ignoring global settings Pros
Cons
|
No problem at all and absolutely no rush! :) Thanks for pushing up the code, it's looking great from an initial glance! I'm busy this evening but I'll take a closer look and answer your questions tomorrow/this weekend! |
|
Good question about the granular settings. I think I'm leaning towards "Granular setting decides" but with the following difference:
I think the flexibility we'd gain with this approach follows the idea that the lowest level settings/config have the most priority which imo outweighs the cons. And as you pointed out, it still ensures no data is lost. This is just my initial thought - I need to think about it a bit more though as I may have missed something! :) wdyt? |
jonnydgreen
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great so far!! 🚀
| if rich_text_render_enabled: | ||
| var text = ParleyUtils.richtext_renderer.render(next_node.get('text')) | ||
| next_node.set('text', text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just FYI, we may need to coordinate with this PR here: #28
I was thinking about it earlier and reading around for best practices and I think for the most flexible and easy way of defining translations, the function calls should probably run after the translations are run. wdyt?
|
|
||
| static func render(text: String) -> String: | ||
| var processed := text | ||
| var result := function_regex.search_all(text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! I was gonna ask about multiple expressions!




Rationale
I've opened this PR because I love this project but comparing it with other libraries I'm seeing some built-in features that are missing (maybe I'm wrong!). The big one for me are dynamical texts, for example an actor changing the displayed name (without creating another actor) or being able to change a text based on the character name. Something like:
"Hello {{get_player_name()}}" => "Hello Alice"
* Conditional option in which the MC may ask the name of an NPC * -> "???: I'm Alice" -> "Alice: Now that you know my name [...]"
The first one there is no way to do it without modifying the default behavior, the second one is possible only with verbose graphs adding a completely duplicated path, if the mc asked then the actor name will be "Alice" Otherwise "???".
With this functionality we can keep the name as {{get_npc_name()}} and it can change dynamically
Code
The implementation is inspired by the idea of enabling the developer to enclose function calls inside double brackets and execute it. The code uses regex to search for the desired pattern (very broadly, does not check for syntax correctness) and then identifies the function that will be called and the arguments. => fun() OK, fun("HI") OK, fun("HI".asdasdas) OK
It will then parse using str_to_val to validate the function parameters
Issues
I see two big issues with the current state of the PR: