replique 0.3.0

A pure Rust dialogue system
Documentation

Replique

Crates.io Docs.rs Crates.io Docs.rs Book License

Replique is a pure Rust dialogue system, with first-class support for Bevy. Dialogues are written in plain text files, with branching choices, variables, conditions and loops, and they reach into the game through commands, functions and tags. A command line checker and a language server report mistakes before the game is ever run.

It is inspired by YarnSpinner, YarnSpinner-Rust and Godot Dialogue Manager.

Read the Replique Book to learn the dialogue language and how to use it in a Bevy game.

A dialogue

:= start
[let $gold = 12]
// `Merchant.Price` queries the game directly: it is the `Price` component
// of the entity named `Merchant`, read at the moment the line is played.
Merchant: Welcome, traveller! A lantern is [Merchant.Price] coins. #happy
-> What do you sell?
    <=> wares
-> Buy the lantern [if $gold >= Merchant.Price]
    [let $gold = $gold - Merchant.Price]
    >> give("lantern")
    Merchant: A fine choice, [$gold] coins left for you.
-> Leave
    => END
Merchant: Safe travels!
---

:= wares
Merchant: Lanterns, rope, and the best apples in town.
// `has` asks whether that same entity holds a `Tired` component.
[if Merchant has Tired]
    Merchant: But I am closing soon.
---

A file is made of nodes. This one reads the components of an entity of the game without any glue code, and also holds a variable, lines with values inserted in them, a tag, a group of choices of which one is only available with enough gold, a command for the game to run, and a jump to another node that comes back.

In Bevy

cargo add bevy_replique

A .rep file is an asset, a running dialogue is an entity, and the game talks to it with messages:

use bevy::prelude::*;
use bevy_replique::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(RepliquePlugin)
        .add_systems(Startup, setup)
        .add_systems(Update, show_line)
        .run();
}

fn setup(
    mut commands: Commands,
    assets: Res<AssetServer>,
    mut start: MessageWriter<StartDialogue>,
) {
    let dialogue: Handle<RepliqueDialogue> = assets.load("dialogue/hello.rep");
    let runner = commands.spawn(DialogueRunner::new(dialogue)).id();

    start.write(StartDialogue {
        runner,
        node: "start".into(),
    });
}

/// Prints every line, then asks the runner to carry on.
fn show_line(
    mut lines: MessageReader<DialogueLine>,
    mut resume: MessageWriter<ResumeDialogue>,
) {
    for line in lines.read() {
        println!("{}: {}", line.speaker.as_deref().unwrap_or("-"), line.text);

        resume.write(ResumeDialogue {
            token: line.token,
            input: ResumeInput::Advance,
        });
    }
}

Choices, commands, functions and the rest are covered in the book, and the examples are runnable:

cargo run -p bevy_replique --example bevy_simple

Crates

Crate Description
replique The engine-agnostic parser and dialogue runtime
bevy_replique Bevy plugin built on top of replique
replique-cli replique check, to lint dialogue files
replique-lsp Language server, for diagnostics as you type

Versions

Replique Bevy
0.3 0.20
0.2 0.19
0.1 0.19

License

Dual-licensed under MIT or Apache-2.0, at your option.