GithubHelp home page GithubHelp logo

godot-journey's Introduction

godot-journey

This project is my attempt to create an Articy: Draft / Twine / YarnSpinner-like experience for Godot Engine 3.x.

For an updated list of the proposed features, see the Core API Overview.

The features these systems provide include a narrative database, a level planner, an interactive dialog system that has access to both of the previous elements, and a nestable graph-based overview of the scenes in your narrative.

The intended roadmap for THIS plugin involves the consolidation of 3 or 4 independent plugins:

The first plugin is for a backend, generic, narrative database...

  • Initially provided templates might include:
    • Character
    • Life (plants, wildlife)
    • Place (things where concepts can BE)
    • Object (non-living thing)
    • Idea (abstract thing: Lore, History, Philosophy, Knowledge, etc.)
  • Users could define templates in the form of script files with exported properties.
  • Setting a script onto a Resource object which stores the data allows you to easily define new templates / edit existing templates for a given concept.
  • These Resource objects could then be serialized in one of two ways, depending on the version of the plugin installed:
    • Users could opt for a .res/.tres-based local storage. Simplest, fastest, most intuitive.
    • Users could opt for Neo4j Graph Database storage. The plugin would ideally come with some standalone version of the database so that C# drivers could access it. In this scenario (if it's doable), Resource objects would be serialized into Neo4j nodes.
      • The advantage of this option is that you get MUCH more sophisticated querying capability with the Cypher query language, essential for large projects.
      • I even have thoughts about composing Cypher queries using a scene file since GraphNodes and their connections can be used to represent an actual Cypher query.
  • Regardless of which method is used, the plugin would include a graph-based editor for this content that mirrors Neo4j systems:
    • Every created concept appears as a node (GraphNode). Every concept has a script attached detailing its available properties.
    • Users could click on any GraphNode to see the properties associated with the type in the Inspector.
      • We could also (POSSIBLY) implement functionality to expand/collapse the GraphNode with the properties in-lined rather than having to view them in the Inspector, but that'd be a lower priority.
    • Relationships can be created between nodes. Every relationship must have one and only one label. They may also have any number of properties.
      • Neo4j natively supports Relationships, but in the .res version, you'd probably have to store each relationship type as its own dictionary in a singular .res file for all relationships, e.g. one dictionary for lives_with relationships mapping one node to another node, etc..

With this database accessible, you could then have another plugin for a graph-based story editor.

  • users could then do screenwriting using an interface akin to Twine or Yarn.
    • The user is presented with a graph in which they can create Passage nodes.
    • Every Passage includes a TextEdit for a narrative scripting language (similar to Harlowe or SugarCube in Twine).
      • I'd want to add word-wrap support to the TextEdit node for this.
      • I'd want the scripting language to...
        • Have lines starting with @character_name: dialogue text
        • Lines without a speaker-identifier (: dialogue text) would be judged as simply having no speaker.
        • Programmers could define accompanying visual/audio data references based on the speaker.
        • Allow @character_name(...): dialogue text to let users provide parameters for manners of speech, directed speech, etc., trigger voice cues, animations, etc. (user-defined).
        • Allow users to inline GDScript code to be called before/during/after the dialogue is triggered.
        • Allow users to inline logic testing, variable assignment, and flow control (perhaps via macros?) to modify which text is displayed.
        • Allow users to define their own custom macros bound to custom GDScript functions.
        • (Example at the bottom):
    • Groups of Passages are organized into Sequences (GraphEdits) which can be figuratively nested into each other
      • A project will have one StoryScript singleton.
      • A StoryScript will have 0 or more Stories which establish a shared source of information about a story.
      • A StoryScript will have 0 or more Sequences which each rely on one Story (often the same).
      • Sequences are broken down into sub-Sequences (they can figuratively be instanced within each other).
      • ^ note that GraphEdits cannot be nested within each other which is why we ultimately keep all Sequences / sub-Sequences as unique children of the Story under the StoryScript singleton. No ACTUAL instancing within each other occurs.
      • Sequences ultimately break down into Passages, the GraphNodes for story content.
      • Users will be able to refer to Sequences in the Scene dock.
      • A dedicated node for Passage and another dedicated node for PackedSequence will exist where the Sequence simply simulates a singular GraphNode with all the inputs and outputs of an entire Sequence GraphEdit.
      • If you "open" a PackedSequence node, it switches you over to the appropriate Sequence GraphEdit (similar to how nested scenes work).
    • A StoryScript singleton could be used to manage data for the story and interact with Sequences.
      • Discrete pieces of StoryScript are executed in their entirety by calls to an advance() function in the StoryScript singleton.
      • Sequences of pieces can therefore be animated by the AnimationPlayer when animating calls to the function.
    • I'm THINKING I might be able to try and retrofit the gdscript module to create some sort of StoryScript module similarly. That way you can still in-line GDScript in some way.
    • StoryScript would ultimately need to be able to compile into a data format, possibly a variation of .twee or use JSON, so that people can use a text editor to view the entirety of a story.

Since all of this gives us a database of content (1 of 2 plugins) and a micro-level story editor (another plugin), we therefore need a macro-level quest editor to connect it all to data-based objectives.

  • Content in the game is defined by Task objects. You can make user-defined Tasks.
  • Users can add Tasks as prerequisites or as objectives for a Quest.
    • users could then tie in task_completed or quest_completed signals into StoryScript Sequence activations.
  • Quests of this sort would be developed within VisualScript probably, and there'd need to be a GDScript variant for text-based development (if it is desired).

These 4 plugins in total form the consolidated Quest editing tool

StoryScript example:

                                                # Note that any set of 4 consecutive spaces are replaced with tabs and all tabs are removed prior to interpretation 
# Bob and Sam are sitting on a couch at home.   # a one-line comment
@Bob:                                           # a persona identifier. It refers to a node that is the child of the StoryScript singleton
    I really wish I had a cheeseburger.         # visible text dialogue.
<% #inlined GDScript                            # non-visible GDScript code to execute
    Story.wants_cheeseburger = true             # variable setting
    Story.drink = "Dr. Pepper"                  # ^
%>                                              # ending tag
                                                # an empty line indicates termination of a discrete unit of dialogue. The text as it will appear on screen in a dialogue box is now: "I really wish I had a cheeseburger."
Honestly, if I couldn't eat                     # another visible line
<<if Story.wants_cheeseburger>>                 # flow control via macros
    cheeseburgers                               # text to appear if true
<<else>>                                        # 
    hot dogs                                    # text to appear if false
<<endif>>,                                      # termination of for loop and a visible comma
<<br>>                                          # a marker indicating a visible line break in the text box
I don't know what I'd do with myself.           # this text shows up on a second line

At the very least, I'd need some
<< echo Story.drink >>.                         # this text inserts "Dr. Pepper" into the text

@Sam(expr="confused"):                          # can define options (key/value pairs) to customize how a line is delivered.
    Seriously? That's all you can think about right now?

    What about the
    <<list Story.fridge.foot <{delay 0.5}>>>    # a custom macro written by users. It executes the same output as the below, commented code
    <#                                          # a start comment tag for macros
    <<for a_food in Story.fridge.food>>         # for loop
        <<delay 0.5>>                           # delays the displaying of the following text output. Directly inserted parameter for macro-powered macros
        <<if a_food == Story.fridge.food.back()>>
            , and
        <<elif a_food != Story.fridge.food.front()>>
            ,
        <<endif>>
        <<echo a_food>>
    <<endfor>>
    #>                                          # an end comment tag for macros
    that we already have...

@Sam(expr="serious"):                           # these lines happen at the same time because there is no newline separating them
    in the FRIDGE?
@Bob(expr="annoyed", voice="mocking"):
    in the FRIDGE.

@Bob(voice="default"):                          # expression is still "annoyed", carries over.
    Yeah, I know.<<br>>I just don't like that stuff.

    There's just too much [green stuff](green_stuff). # Creates a link from this Passage to the Passage with the title "green_stuff".
                                                        # ^ The text shows up as a hyperlink to click, at which point the Passage is triggered.
                                                        # ^ Multiple Passages can be triggered at the same time (allowing for simultaneous conversations).
# It should also be possible to attach Passages to signals so that emitting the signal triggers the Passage.
# StoryScript should be able to query and reference the narrative database, ideally with auto-completion provided.

godot-journey's People

Contributors

willnationsdev avatar

Stargazers

Mounir Tohami avatar Kotob avatar __ avatar Yotopihi avatar Javed Khan avatar miguel avatar  avatar Andrew Dunai avatar Jose Hernandez avatar  avatar David Kincaid avatar David Konsumer avatar Russell Matney avatar  avatar  avatar Brian Jorgensen avatar  avatar Anthony Cossins avatar  avatar  avatar KimSia Sim avatar  avatar  avatar Chris Johnson avatar  avatar Sergey Nikitin avatar DaVinci789 avatar Brett Alistair Kromkamp avatar ShalokShalom avatar Rifat Khan avatar rezgi avatar un0mic avatar Albert Tavares de Almeida avatar Ali-RS avatar  avatar Logan avatar  avatar Martin Velecký avatar Michał Walczak avatar Eryk Miszczuk avatar Todor Imreorov avatar Anthony Free avatar Martin Novák avatar Sergei ZH avatar  avatar Val Packett avatar Louis Pearson avatar Dennis Keirsgieter avatar Johnny Goss avatar Anthony Prince Merluza avatar Andrew Wooldridge avatar Erik Shuttlesworth avatar I'mAHopelessDev avatar  avatar Bernardo avatar  avatar  avatar Krystof Klestil avatar  avatar Mauricio avatar Mohab Abd El-Dayem avatar Jeremi Biernacki avatar Cliffs Dover avatar  avatar  avatar  avatar Josef Frank avatar Michael O'Brien avatar Preston Knopp avatar K. S. Ernest (iFire) Lee avatar Alexandre Araújo avatar Sam Rogers avatar Matthias Stöckli avatar  avatar Nehemiah I. Dacres avatar  avatar Noel Quiles avatar Philipp Wabnitz avatar

Watchers

Andrew Wooldridge avatar James Cloos avatar Ali-RS avatar Martin Velecký avatar  avatar Louis Pearson avatar Calvin Corbeck avatar DaVinci789 avatar  avatar Alexandros Petrou avatar  avatar  avatar  avatar Krystof Klestil avatar rezgi avatar  avatar

Forkers

stoeoeoe un0mic

godot-journey's Issues

Implement a Content system.

Also a StoryItem like Tasks, this is just a way of defining narrative data to be associated with a StoryGraph's nodes. This is any sort of media (text, hyperlinks, StoryItem references, images, video, etc.) which need to be indexed by the CMS.

Create a graph querying API

In all likelihood, I am guessing this would involve a Builder pattern. I've been told by others to look into the NetworkX API from Python as "it would be a good fit for GDScript".

For this particular Issue, we are looking strictly at read operations in the graph.

The Core API Overview

Come chat about the project on the Godot Extended Libraries Discord!

Sources

The ideas that follow stem from a desire to emulate and synchronize features from the following applications into a single, cohesive Godot plugin that may also involve git submodules for the integration of project-specific views, editors, and APIs:

  • Articy Draft
    • Nestable story structures
    • Story database
    • User-Defined editors for story content
    • Map editors (able to mark positions/regions, add metadata that points to database content.
    • System automatically tracks cross-references between story content and database content.
    • Micro-Story Editor: Nodes-and-wires editor communicating dialogue sequences with branching paths and hooks for triggering game logic, etc.
      • Note: supports both low-level nodes/wires at the line of dialogue LOD while also scaling up to bundles of dialogue sequences represented by a single node, etc.
    • Macro-Story Editor: Nodes-and-wires editor communicating when scenes are triggered and their relationships to quests, concrete game tasks, and updates to the database when completed/failed/etc.
    • Able to render statistics about database content.
    • Highly configurable toolkit with a robust plugin system, enabling users to manipulate the tools as they see fit.
    • Has tools to export dialogue lines for any given character, facilitating the business requirements of voice actors by meeting industry standards.
  • Twine / YarnSpinner
    • User-friendly scripting languages to quickly and easily develop narrative content.
    • An intuitive nodes-and-wires interface (on the Passage level). Users write narrative content in a Passage using a scripting language, but the order and linking of Passages are procedurally generated based on each Passages' content including internal hyperlinks to other Passages.
  • Manuskript
    • Dedicated writing tool targeted at writers. Jot down ideas into a central database.
    • Written passages can refer to content in the database, tracking cross-references.
  • Ink
    • Extremely powerful and flexible scripting language for data-generation and execution of branching storylines.
    • Nestable story structures
    • Provides hooks to integrate with external game systems in the Ink Runtime engine.
  • Fountain
    • A simple, Markdown-like scripting language for that emulates a screenwriting workflow
    • Can render to screenwriting scripts for easier reading by actors / voice actors.
  • HackNPlan
    • Can build a Game Design Document containing the core design concepts of the project.
    • Provides Kanban boards, user stories, and other Agile tools for tracking game development tasks.
    • Can render statistics and other metrics on the current project's state related to the necessary tasks.
    • Can render tasks in a variety of views and group them according to subsystem, assigned users, assigned departments, etc.
    • Users can contribute to a centralized database of story concepts and tie them directly to gameplay concepts and development tasks in the Kanban boards due to the shared information.

API Suggestions

Okay, so that was a lot of stuff. What parts of this am I actually suggesting we build into a Godot project? We'll get into it below.

The names of things aren't specific. They're just so that I can refer to them during the course of the proposal.

These are merely idealized concepts / speculated implementations. It's not necessarily true that these are required, but each piece works with the other pieces, so the more you strip away from this API, the less the pieces are able to work together, so they consequently give less benefit. The API is also constructed as it is for maximum performance benefits and re-usability of concepts throughout Godot Engine's codebase.

I have specifically outlined each concept under a single numbered list so that we can reference individual points using their numeric identifiers.

  1. A "Core" Facade Singleton must exist which tracks all story information related to a Godot project.
    1. Virtually all of this information must be serializable and easily written to / read from memory by Godot Engine.
    2. Core must be accessible both at editor-time and run-time.
    3. Core exposes an external interface that adopts the Cypher Query Language API. This implies that Core must expose a model of a graph-based database.
    4. Why a graph-based database?
      1. Writers, designers, and programmers will need to be able to quickly query items that match highly specific, interconnected criteria.
      2. The details of these criteria, in Godot, will be built upon a duck-typed scripting API which does not conform well to the strict tabular layouts of any SQL-based structure.
      3. Cypher is powerful, expressive and user-friendly, all on top of being uniquely well-suited to managing story information.
  2. Users can define data structures which embody their story content: StoryItems, extending Resource (Cypher:nodes). StoryItems can have properties (Cypher:map, Godot:Dictionary).
  3. Users can tag their StoryItems with 0 or more Labels (Cypher:Label, Godot: a user-defined tags system for resources rather than Nodes' groups).
  4. Users can define Relationships between StoryItems (connections) which must each have 1 Label. Relationships can have properties (Cypher:map, Godot:Dictionary).
  5. Users can view any StoryItem and see...
    1. a list of its properties.
    2. a list of its Labels.
    3. a list of its Relationships to other specific StoryItems.
  6. A collection of nodes and connections in this context is called a StoryGraph.
  7. Users can use a centralized API, accessible to GDScript, (extensible via plugins for an aribtrary number of supplemental GUI interfaces) to...
    1. build a CypherQuery, extending Resource, which are queries for StoryItems that match certain criteria and have certain connections to each other.
      1. Example: Up to this point in the Timeline, what are all magical items that, at one point or another, were located in a place visited by the protagonist named "John"?
      2. Query: MATCH (item:MAGICAL:ITEM)-[:LOCATED_IN]->(:PLACE)<-[:VISITED]-(:PROTAGONIST {first_name:"John"}) RETURN item;
      3. Users should be able to build StoryItem queries, through a runtime API, via an Inspector, and via nodes-and-wires (for non-programmers).
      4. One can save these queries and their search results separately, allowing to either refresh with a new search result at any point or to cache a particular query result under an assumed name, respectively.
      5. Given that building a Cypher interpreter and runtime engine that is integrated into Godot directly will take quite a bit of time, I suggest starting with a GDScript prototype implementation base off the Builder design pattern.
    2. execute queries against the database.
      1. 1 or more of these alterations is called an Event, extending Resource. It refers to a discrete collection of changes in the story's state (a Cypher transaction). Modifications to the graph can only happen through Events. If a user executes a query against the graph directly that results in side-effects, then it generates an Event wrapping the query.
      2. Each Event gets a unique hash identifier.
      3. A sequence of Events is wrapped into a Timeline.
      4. When submitted, Events buffer themselves to a queue inside the Core. The StoryGraph is protected by a Mutex. The queue spawns a configurable maximum number of Threads for handling the load of the queue. With the Core managing a queue of requests issued to it from arbitrary external clients, the core is established with a Server pattern, effectively making the core a StoryServer (akin to the other major low-level Servers in the engine).
      5. Flesh out the rest of the StoryGraph, Timeline, and Event API so that it mimics, precisely, the same API as git. StoryGraphs are Repositories. Timelines are Branches. Events are Commits. StoryItems/Relationships are Files. We should be able attach commit messages, merge and rebase events, diff Timelines, reset to alternate Timeline points, branch off into alternate Timelines, etc.
        1. Might consider integrating libgit2 (would need to rework things so it has no Qt dependencies) as a dependency just so that we can rely on using git directly as a "database". Don't know how performant that would be though. Would also be a good opportunity to integrate Git directly into Godot via module.
        2. If we created a way of visualizing branching TimeLines, their associated Events, and the changes associated with each Event, that same code would provide a common API for any arbitrary visual node-based tree or graph of data, including a GitKraken-like visualization of Git content within a Godot Engine project, skill trees (dedicated SkillTree Control node?), charts (dedicated Charts plugin for data visualizations?), and probably plenty more that I haven't thought of yet.
  8. There are a few natural consequences that comes from StoryItem, Timeline, and StoryGraph all extending Resource:
    1. The Core can arbitrarily re-organize how each resource is distributed in the FileSystem.
      1. Are they embedded in a single Resource file so that all of the data is together? This is great for read-only situations where you just pull in all of the data at once.
      2. Do we believe it is likely that a subset of StoryItems A from Timeline T will be edited frequently in the near future? Then let's extract T:A from the StoryGraph file, set it up as an external dependency rather than a set of embedded Resources, and then write them out to their own Resource files. Now, any edits made to them can be read/written quickly, without having to save and load the entire StoryGraph file with each change. Etc.
    2. Because they are stored as Resources, they are still objects.
      1. This means they will read/write smoothly, even as binary files, rather than us having to write a custom API to re-map data types.
      2. The will all have free access to class-wide constants and static functions without impacting storage or performance of the individual records.
  9. Core manages a global, editor-time StoryGraph called Universe which tracks a statically-defined universe of content.
    1. When a Timeline executes against a StoryGraph (i.e. merged), the Timeline is capable of creating content in the StoryGraph. This means that at the beginning, a game could start with a nearly empty StoryGraph (nothing but basic interactions and ideas), an AI can create a copy of the StoryGraph, apply a theoretical Event to develop an alternate Timeline and view the resulting theoretical StoryGraph. From there, it can subsequently reason and analyze about this theoretical StoryGraph to examine their state before pursuing them as a Plan in a Goal-Oriented Action Planning API. Makes it much easier to create AI-driven narrative experiences.
  10. Users must be able to build and configure GUI editors for editing the data associated with their game's content.
    1. This is so that the developer for a project can construct custom GUI editors for their writer/designer team members.
    2. The plugin would provide a default set of editor templates which could then be edited by users, ideally with as little effort and/or as much detail as desired.
      1. Have drag-and-drop features for basic CRUD operations related to data AND editors. A writer or designer should be able to feel comfortable doing all the same work a programmer does when designing data structures in a text file.
  11. Core's git-like API can be abstracted into a variety of sub-projects that rely on the same basic infrastructure. It wouldn't be that much of a stretch to incorporate a full-blown Game Design Document (including information beyond just story, but also gameplay systems, etc.) and task-managing systems that have direct access to the Game Design Document information, effectively building an integrated, homegrown HackNPlan super-system. And what is a quest system but a sweet RPG wrapper around a task management system?

This is what I envision for godot-journey. It would serve as a basis for any and all future story management plugins as other plugins would merely create a particular visualization - like Rakugo's Phone Mode, or interface - like Rakugo's GDScript API or future RakugoScript, etc. and add to the available ways of interacting with the Core.

Implement a Quest/Task system

We're gonna need a quest system if we're gonna plan to build RPGs of any sort using Journey. To that end, we'll need a robust, extensible framework for planning and organizing tasks.

This is important since we can look not only to RPGs in the game industry, but also professional project management software like Trello, Jira, and GitHub as examples of intelligent ways to organize task management software. After all, quests are just organizing player tasks.

We should endeavor for our quest system to not be opinionated, but rather produce a very low-level API that can be extended into an arbitrary number of forms.

So, let's first breakdown a basic API:

  • Tasks should be serializable in some capacity.
  • Tasks should implement the Composite pattern, for maximum nesting capability.
    • This means that Tasks will have a "parent" and a "collection" of child Tasks.
  • Tasks should have a collection of states (a Dictionary) that they can be in. This collection of states should be user-configurable. Users should also be able to define the set of transitions that are allowed between states.
    • There should be signal emitted when a Task changes state.
    • We should have a built-in callback, _state_updated(state), that is called whenever a state property is modified to a different value.
    • We can outsource this implementation into its own FSM implementation. Fortunately, I already have an experimental branch of Godot Next that does something like this.
  • Tasks should be StoryItems which can have Labels attached. For example...
    • "archived"
    • "ready"
    • "submitted"
    • "kill"
    • "fetch"
    • "travel"
    • "escort"
  • Tasks can have relationships to other StoryItems, for example...
    • "created_by"
    • "completed"
    • "active"
    • "bookmarked"
    • "submitted"
  • One can configure Tasks to loop. If true, then completing the task will simply emit a "state changed" signal and then re-clear the child Tasks
  • One can configure Tasks to lock. EDIT_LOCKED, EDIT_UNLOCKED, and EDIT_INHERIT will function similar to the PAUSE_STATE values in Node. While locked, any attempt to transition from the state will be blocked.
  • Similar property for whether a Task is visible.
  • Each Task can individually be assigned a TaskSystem which describes all of the information about the type of Task it is. By default, they inherit the task system of their parent.
  • Can configure dependency relationships between Tasks:
    • When Task no. 123 transitions to state X / becomes (un)locked / becomes (in)visible, trigger Task no. 456 to transition to state Y / become (un)locked / become (in)visible.

Create a Journey Facade Singleton

Make a Journey singleton class. This means that you'll really create a _Journey C++ singleton and then you'll make an exposed Journey class with static functions that interface with the non-exposed _Journey singleton.

Journey will...

  1. Provide a getter for its internal StoryGraph.
  2. Provide a means of registering global properties.
    1. It will cache subsets of properties that use slash delimeters. That is, it will need a HashMap<StringName, Variant> that stores properties like "chapter1/found_doctor" => true, using a 1-to-1 mapping. And then, it will also store another HashMap<StringName, Set<StringName> so that it can report on which properties exist within the "chapter1" namespace, etc. If multiple slashes are present, then everything leading up to the final slash is considered a single key.
    2. It should be able to bind property names to any arbitrary StoryItem in the graph.
  3. It will provide a wrapper around all Dialogue, Content, and Task APIs.

Overall, Journey acts as a Facade for all of the internal operations related to the Journey API. We may also want to consider having it mimic the StoryGraph's API since it only has 1 graph and we may wish to hide the underlying implementation of Journey from the end user. Something to discuss.

Implement a Dialogue system.

Similar to Task system. Speaking strictly from a backend position, these will be stored in a cyclic graph as nodes. If a dialogue option gives an opportunity to move to another line of dialogue this generates a connection between those nodes. Should be able to encapsulate bundled nodes which refer to a subset of a graph (a node can be 1 line of dialogue or represent multiple lines of dialogue). Need to be sure to avoid infinite cycles here.

Multidialogue nodes will automatically portray themselves as composite nodes which maintain transitive connections to relevant other nodes, i.e. these will be fake connections. If you ask for the connections associated with a composite node, it will simply loop through the internal nodes and compile a list of connections before returning references to those connections. It doesn't actually store new connections in the data.

Dialogue nodes' statements can be connected to Expression nodes. All expression nodes are tracked such that one can form a tabular list of all expressions and keep tabs on which Properties, Content, Tasks, or other StoryItems they reference.

Action nodes allow user-configurable actions to take place which are triggered by the dialogue system. These are likewise tracked.

Need to leave open the possibility of executing multiple lines of dialogue at the same time. Even if a web of dialogue tracks exist, one may have multiple Conversation instances that are actively traveling through the web's data. This is to support scenarios where a player walks through an environment and multiple NPCs in the background are talking with scripted sequences, based on conditions, even while the player is engaged in other scripted conversations/cutscenes.

Lines of dialogue may have an arbitrary number of speakers. Maybe there is no speaker, maybe there are several. Users should be able to bind labels, properties, and actions to any single dialogue node. Some minor level of scheduling of actions in relation to a dialogue node should be available (not restricted to only "execute action when the dialogue begins").

This is not a GUI for a dialogue system. It is a backend that could very well support a variety of GUI and text-based systems. We should provide some as part of Journey, but those will be other tasks to complete down the road.

Implement an API for users to define their own scripting languages.

This involves integrating peglib as a thirdparty library via NativeScript. With it, someone can just assign a String to it to generate an internal grammar and then call methods on the parser that will parse text according to the described grammar.

This will then make it much easier for people to devise their own scripting languages for integrations like Twine/Harlowe, Ink, RenPy, Markdown/Fountain, etc.

Create a branching narrative API.

If you know git, then great. We're building a git API from scratch, that only runs at runtime (no file I/O) and which specifically targets changes made to a graph.

"Events" : "commits"
"Timelines" : "branches"
"StoryGraph" : "repository".

Now, in detail:

  1. Events, a discrete collection of changes to the story graph.
    1. Any given Event can be committed or reverted, like a git commit.
    2. All Events have a unique hash ID.
    3. Events are immutable. You can create two different Events that execute the same changes, but they will still have unique IDs. Once created, they cannot be edited. You can make batched changes from an existing Event (execute a query against the graph state it represents) and the diff'd result will generate a new Event (like a git commit amend).
    4. We will need an EventBuilder object to simplify/speed up their creation. Events should then probably allow one to create an EventBuilder based on their collective changes, to begin building a new Event from that state.
  2. Timelines, a wrapper around a Vector<Event> (consider stealing the vector class from the Godot source code).
    1. Timelines, when created, branch off of an existing Timeline and keep track of which Event they were created after. This is called the Timeline's "base" Event.
      • To create a StoryGraph, we will need an initial Event with a "Story created" change or something which will serve as the base for any subsequent Timelines off the master timeline.
    2. Timelines can insert their events into a target Timeline via a merge: insert each individual Event into the target Timeline after the base event. A merge operation will return a TimelineConflict object or null if no errors.
    3. Timelines can rebase, i.e. change their base event to a different event from a different Timeline. In this case...
      1. the previous base event must exist in the target Timeline.
      2. the source Timeline will replay its Events on top of the target Timeline and will return a TimelineConflict object or null, if no errors.
  3. A StoryGraph will provide a wrapper API for transitioning between Timelines and committing/reverting Events, i.e. it provides a git-like API.

Add a graph library

Integrate a graph library to start work on building a graph-based story database.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.