Godot: Generic Sequential Text Scripting Engine

Created on 3 Dec 2018  路  15Comments  路  Source: godotengine/godot

Issue description:
I've seen and thought of many different approaches to developing a dialogue system in Godot. There are a great many methodologies and use cases people have proposed:

Many of these applications share basic API commonalities though:

  • Maintaining a conversation (an independent sequence of scripted text/audio content, possibly accompanied by other animations/behavior), while potentially allowing for multiple "conversations" at one time (what if two people start talking to the player character at the same time?).
  • Creating text in dialogue boxes that follow accessibility standards:

    • Scale text appropriately based on the environment's resolution.

    • Page text appropriately based on the environment's screen dimensions and font size. Prevent text content from line-breaking or paging mid-word.

    • Render text on top of background content clearly while maintaining a minimal visual footprint. Potentially detect (and warn) when displayed text will not be clearly visible based on font color / color of background.

    • Potentially allow users to access previously displayed text (logs of dialogue or messages).

    • Display warnings to the user when dialogue boxes are not displayed on-screen for a sufficient length of time to be read.

  • Maintain variables/constants that are shared across a story.
  • Notify other systems when certain changes occur (a particular dialogue section is reached, the dialogue box / audio has advanced to the next bit of content, the conversation has concluded, etc.).

Each "approach" that a user might use will have differences in how the data is (de)serialized, what kind of editor is used to modify the deserialized data, and how the data is rendered visually (if the narrative scripting API is even involved in that process at all). However, all of the above commonalities...

  1. apply to each approach to the problem,
  2. are difficult to implement on one's own, and
  3. are applicable to any game that involves decent amounts of text content.

I believe the engine could benefit from having a narrative engine module of some sort which plugins could then leverage as a unified API when 1) plugging in data and 2) determining how to render the content within the narrative engine.

Making such a system be its own GDNative plugin is somewhat awkward as it is really only useful if all relevant plugins can make an assumption that the unified API will be there.

Edit: (To clarify from Zylann's comment) I am suggesting that the engine provide an abstraction layer over whatever API these dialogue systems might need. Otherwise, if one writes code that interacts with 1 dialogue system, they can't then turn around and use that same code to interact with a different dialogue system on a different project, since each dialogue system provides its own API written by the plugin's or narrative scripting language's creator(s).

WDYT?

archived discussion feature proposal core

Most helpful comment

I tend to side with @Zylann as this sounds a lot like the kind of "future proofing" that we really try to avoid in Godot. Developing an abstract interface for something that may be used by different plugins for a common goal rings all kinds of alarms. You can't know that those plugin developers will actually use said API, and designing it will be complex if it's only speculative.

The proper approach is to provide a base plugin that other plugins can build upon, then work on the latter to port them to this new base plugin to validate its usefulness (because until then it will just be a nice, unused abstraction). This process will imply changing the base plugin to fix all its shortcomings and have it fulfill the similar but different needs of a wide variety of use cases... And eventually it may turn out that this abstraction is good and works for all use cases, in which case it could be considered for inclusion in the core engine. Or it may turn out that such a framework can't be generic enough to match the use cases of all dialogue systems, and it won't be used much/at all.

TL;DR: If dialogue systems can be done without having an abstraction in the core engine, we shouldn't add one. If a community-provided abstraction plugin ends up being so popular that all dialogue systems rely on it, and that having it in core would be a huge usability improvement, then it might be worth considering.

All 15 comments

Here is what I think: from the point of view of a general-purpose engine such as Godot, I find this still quite specific and games always have X and Y which makes it partly impossible to re-use the exact same system for everything.
I'd say if the problem is about sharing compatible data across editors, you then need a standard first rather than a generic system implemented in the engine that everyone would have to build upon. But that's just what I think ;)

@Zylann

games always have X and Y which makes it partly impossible to re-use the exact same system for everything.

I'm confused. If there are commonalities to be found between games' APIs, then wouldn't creating a re-usable system as a unified API be the exact thing one would want to do if they wish to abstractly refer to these dialogue systems without caring which one is being used?

I'd say if the problem is about sharing compatible data across editors, you then need a standard first rather than a generic system implemented in the engine that everyone would have to build upon.

This isn't so much about the data format as it is about the actual behavioral API. The same way that the engine's Script interface mandates a common API for

  1. accessing script variables.
  2. calling script methods.
  3. getting the base script.
  4. determining which language the script belongs to.
  5. what the name of the script type is.
  6. which class the script is extending.
  7. etc.

I would expect to similarly be able to interact with a dialogue system API without needing to know the details of how that API is storing its data or rendering itself. In MVC terms, I think there is need for a centralized controller API. The narrative scripting languages can independently determine their own model and view content, so long as it can conform to the abstraction layer defined by the engine. GDScript, CSharpScript, and VisualScript each store and present their data in vastly different ways, but we can always use get_instance_base_type() and get_language() on them regardless.

I would likewise wish to see a similar API for...

  1. setting up an array of text content.
  2. advancing through text sequences
  3. seeking to arbitrary sections
  4. retrieving a log of conversations
  5. make "choices" that divert the flow of conversations and get a log of what choices have been made, and how many times they have been encountered
  6. check what metadata changes, if any, may be associated with making a choice
  7. checking the status of story-related variables, editing them, and/or seeing how they have changed over time.

This would all be in addition to creating a dedicated node for a "smart" text dialogue (similar to the RichTextLabel, perhaps extending it, but which can handle the scaling, paging, and warnings described in the OP).

The "big" debate about this is really whether or not we should develop something like this as a plugin, and then just make other plugin developers decide whether to match the API abstraction or not (which creates arbitrary work for the plugin creators and leaves all of the APIs fragmented which hurts users) or whether we bind a centralized interface to the engine with a module and invite plugin creators to extend from or use these classes when building their own dialogue systems (helps users by encouraging everything to be consistent, but also adds another piece to the engine which could arguably be kept as its own GDNative plugin).

Regardless of whether a dialogue system abstraction is included, having a text label node that is smart enough to execute on the accessibility features would be a great boon in and of itself. (This issue is kind of 2-in-1. Whoops).

Sorry I've been a bit elusive, I was mostly speaking about integration in engine. I tend to often freak out when a "solution to everything" is presented for something surely common in games but having wide ranges of implementations. Though I admit I don't use dialog systems often, this also makes me think of state machine tools as well, but specialized for dialogs.

I still see this as a plugin tbh, because obviously not every game needs this to the point it has to be abstracted, and I don't see strong technical limitations that would force it to be integrated in the engine (at least, if it were only for dialog system). But also, why GDNative? You mentionned it in the first post but I wonder why would it be a requirement instead of a regular GDScript plugin? Is it because of the potential use of a system that uses a different programming language?

I see the main advantage is that users could call a common abstraction layer so they can use whatever text scripting engine behind it, making code easy to share (if even wanted, since switching two backends might not always work out 1:1). Again I'm not strong user of these systems, but I think such abstraction layer should be given a go as a plugin first. Firstly because I don't see a strong technical reason for it to be in engine directly, and secondly because of the freedom to just do it and share it. It helps a lot to iterate and see if that works out. If that's a need, perhaps someone already came out with such an API? Then, once an API is found, it could be added like we added AR/VR (thought again, that one was added because of technical needs).

What might go in core more easily though, would be small features like you just described with text controls. When I worked on terrains I quickly realized it would not go built-in anytime soon as a whole, because of the too many ways to approach it in a generic way, even though there could be many good reasons to have it integrated. So that didn't prevent from PRing small technical features that make it easier to build (heightmap collider, partial texture update, texture arrays, custom loaders, custom bounding boxes...).

Oh yeah, not sure why I specified GDNative. I could easily see a plugin implementation being in GDScript. And I get the approach of making a generic system be a plugin first if only to refine it. Then, IF enough people would like to see such a unified API be integrated, then convert said plugin into a module that comes bundled. That sounds like solid reasoning to me.

I guess I'll leave this open for a bit in case anyone has dissenting opinions, but will close it after a while if no one objects.

i have no idea what i just read. but the idea sounds good, iuno if it will get added to the core. but i'm in favor of a Dialog System node. although it could be created with gds and just be saved as a separate scene and then just instanced. but as an official addon or whatever, i think its cool

@girng if by "core" you mean the main engine repo, then that's the topic at hand. The question is really more of an abstract one than anything: if multiple plugins (context: "dialogue systems") all provide a feature set without a common API, and we want such plugins to have a common API to follow, then should that API be implemented into the engine, or should it be relegated to a plugin of its own.

@willnationsdev yeah. i remember discussing something similar with you 6+months or ago. ability to use gdnative so stuff like this can be added w/o being "officially added/support by the core engine". that could also act as a solution to "can this be added to the core engine" problem. i believe godot-next is that solution. i just starred it btw, forgot to re-star after i made my account again.

I tend to side with @Zylann as this sounds a lot like the kind of "future proofing" that we really try to avoid in Godot. Developing an abstract interface for something that may be used by different plugins for a common goal rings all kinds of alarms. You can't know that those plugin developers will actually use said API, and designing it will be complex if it's only speculative.

The proper approach is to provide a base plugin that other plugins can build upon, then work on the latter to port them to this new base plugin to validate its usefulness (because until then it will just be a nice, unused abstraction). This process will imply changing the base plugin to fix all its shortcomings and have it fulfill the similar but different needs of a wide variety of use cases... And eventually it may turn out that this abstraction is good and works for all use cases, in which case it could be considered for inclusion in the core engine. Or it may turn out that such a framework can't be generic enough to match the use cases of all dialogue systems, and it won't be used much/at all.

TL;DR: If dialogue systems can be done without having an abstraction in the core engine, we shouldn't add one. If a community-provided abstraction plugin ends up being so popular that all dialogue systems rely on it, and that having it in core would be a huge usability improvement, then it might be worth considering.

That being said it's fine to use this issue to gather input from developers of dialogue systems and narrow down what such a "one size fits all" abstraction level could be like, even if it ends up developed someplace else eventually (at which point discussions should move to its new home).

@akien-mga I think it may be prudent to create a godot-docs article that contains a re-iteration of reduz's "this is what kind of content gets accepted in a PR" blog post, that way it can be updated with additional information (like this Issue) over time by the community. Would definitely help people get a better idea of how to properly participate.

Contributions are considered rejected until proven useful. There are no hypotheticals here and we never accept something because it might be useful. Functionality is merged only when there is a valid and proven real-life use case for it. This means that someone (and especially more than one user) needs this new functionality for their actual projects, in order to save considerable amounts of time _or just because it's otherwise impossible to advance development without it._

the last sentence is really a defining statement. most feature requests can already be done with gdscript/node scene system already. thus, they might fall under the second clause in the last sentence. not saying this particular issue is relevant to that, just saying in general

that's how i interpret it (not sure if my interpretation is the right way, but yeah)

Can't we create a simple plugin/plugins with separate implementation ideas and add it to Godot and share and sort of A/B Test to see what works and if it works???
Cause it's really hard to say what the majority will like/need from a sample size of 10-20 devs that see this thread.

I'm looking at GodotTIE and it actually does quite a bit of an API on its own (as a "text interface engine", it makes sense). I may try to talk with its author about refactoring it to separate the UI from the actual interface at some point. Would love it if that repo could become a larger project to showcase an array of dialogue tools.

Feature and improvement proposals for the Godot Engine are now being discussed and reviewed in a dedicated Godot Improvement Proposals (GIP) (godotengine/godot-proposals) issue tracker. The GIP tracker has a detailed issue template designed so that proposals include all the relevant information to start a productive discussion and help the community assess the validity of the proposal for the engine.

The main (godotengine/godot) tracker is now solely dedicated to bug reports and Pull Requests, enabling contributors to have a better focus on bug fixing work. Therefore, we are now closing all older feature proposals on the main issue tracker.

If you are interested in this feature proposal, please open a new proposal on the GIP tracker following the given issue template (after checking that it doesn't exist already). Be sure to reference this closed issue if it includes any relevant discussion (which you are also encouraged to summarize in the new proposal). Thanks in advance!

Was this page helpful?
0 / 5 - 0 ratings