Blabber
Are you a modpack maker who wants their players to talk to more than a quest book? Are you a modded server owner who wants to sprinkle some ✨immersion✨ in their world? Are you perhaps a modder who is looking for an easy-to-use dialogue library with expansive tooling?
Blabber is a mod and library for displaying interactive dialogues to your players. Just write your dialogue description files, then start them on demand!
How it looks
Like that:
Or like that:
You get to choose per-dialogue.
How it works
Commands
Blabber adds the /blabber
command, allowing server operators and mapmakers to interact with the mod through commands.
/blabber dialogue
/blabber dialogue start <dialogue> [<targets>] [<interlocutor>]
: Starts a dialogue for one or more players.<dialogue>
: the unique identifier for the dialogue[<targets>]
(optional) : If specified, must be either a player’s username or a target selector. If unspecified, defaults to the player using the command. When used in a command block,[<targets>]
is not optional.[<interlocutor>]
(optional) : If specified, must be a target selector for a single entity. If unspecified, defaults to no interlocutor.
Format
Blabber will automatically load all JSON files in the data/[namespace]/blabber/dialogues
directory.
If you are making a mod, the data
directory in question is in src/resources
, next to your fabric.mod.json
or quilt.mod.json
.
Otherwise, if you are making a datapack, this directory is at the root, right next to your pack.mcmeta
.
These files will also be reloaded when running /reload
, just like tags and functions.
Each file describes the various states a dialogue can be in. Here is a super basic example:
This dialogue has 5 states: start
, accept
, end_success
, refuse
, and end_failure
.
When a player gets this dialogue, they will first be shown “Do you want potatoes?” with the options “Yes please!” and “No thanks.”.
-
If they click “Yes please!”, they will switch to the
accept
state and be shown the text “Alright, have potatoes” with the only choice “ok”. When they click on that choice, they will switch to theend_success
state, which ends the dialogue. -
If they click “No thanks.”, they will switch to the
refuse
state and be shown the text “Are you sure?” with the choices “yes” and “I changed my mind.” being available.- If they click on “yes”, they will switch to the
end_failure
state, which also ends the dialogue. - However, if they click on “I changed my mind”, they will switch to the
accept
state, and be shown the same text and only choice.
- If they click on “yes”, they will switch to the
Of course, this would be quite useless if we didn’t give the player their potatoes.
We can fix this by adding an action to the end_success
state; a command action with the value /give @s potato 12
should do nicely.
Here’s the JSON file corresponding to what we just described:
basic-dialogue.json
{
"$schema": "https://ladysnake.org/schemas/blabber/dialogue.schema.json",
"start_at": "start",
"states": {
"start": {
"text": "Do you want potatoes?",
"choices": [
{ "text": "Yes please!", "next": "accept" },
{ "text": "No thanks.", "next": "refuse" }
]
},
"accept": {
"text": "Alright, have potatoes",
"choices": [
{ "text": "ok", "next": "end_success" }
]
},
"refuse": {
"text": "Are you sure?",
"choices": [
{ "text": "I changed my mind.", "next": "accept" },
{ "text": "yes", "next": "end_failure" }
]
},
"end_success": {
"type": "end_dialogue",
"action": { "type": "blabber:command", "value": "/give @s potato 12" }
},
"end_failure": {
"type": "end_dialogue"
}
}
}
Text
Texts in dialogues use the standard minecraft text format.
A couple of things to keep in mind :
- you can write
\n
in text literals or translations to make a new line - fancy text content like entity selectors should work as expected, however they are resolved only once at the start of a dialogue (which means if you use a “nearest entity” selector and entities around the player move, the selector will keep targeting the one that was closest when the dialogue started)
Layout
As noted in the previous section, you can choose if your dialogue uses the classic layout, or the RPG layout (first and second screenshot, respectively).
The JSON looks like this (goes at the top level, replace "blabber:classic"
with "blabber:rpg"
for the alternative look):
Simple layout JSON
{
"layout": {
"type": "blabber:classic"
}
}
Illustrations
Starting with version 1.5.0 of Blabber, dialogues can make use of illustrations - graphical content that help bring them to life 🧑🎨
Illustrations can be set for a regular dialogue state, or for individual choices within a state. In the former case they are positioned relative to the window, in the latter they are positioned relative to the choice’s text (which is notably useful to keep up with localization shifting those around).
There are currently 3 types of illustrations, plus the group type:
Illustration Types
Item (blabber:item
)
Renders an item stack with optional NBT. Properties:
item
(type:item stack
): the data for the item to renderx
(type:integer
): theX
coordinate for rendering the stack on the screeny
(type:integer
): theY
coordinate for rendering the stack on the screenshow_tooltip
(type:boolean
, optional): if set totrue
, will render the item tooltip when the illustration is hovered in the dialogue screen
Entity (blabber:entity
)
Renders an entity taken from the player’s world, in a frame similar to the inventory’s player rendering. Properties:
entity
(type:string
): an entity selector (compatible with@interlocutor
). If this selector finds nothing at the time the dialogue starts, the illustration will not be drawn.x1
(type:integer
): theX
coordinate of the frame’s upper left cornery1
(type:integer
): theY
coordinate of the frame’s upper left cornerx2
(type:integer
): theY
coordinate of the frame’s lower right cornery2
(type:integer
): theY
coordinate of the frame’s lower right cornersize
(type:integer
, optional): the scaling factor for the entity (1
is the default size)y_offset
(type:decimal number
): how far down the entity should be pushed within the framestare_at_x
(type:integer
, optional): theX
coordinate, relative to the frame’s center, towards which the entity should look. If left unspecified, the entity’s stare will horizontally follow the player’s cursor.stare_at_y
(type:integer
, optional): theY
coordinate, relative to the frame’s center, towards which the entity should look. If left unspecified, the entity’s stare will vertically follow the player’s cursor.
Fake Entity (blabber:fake_entity
)
Just like blabber:entity
, but renders a fake entity of the desired type, with optional NBT. Properties:
id
(type:string
): the ID for the entity’s type (e.g.minecraft:villager
)data
(type:object
, optional): NBT data to apply to the rendered entityx1
,y1
,x2
,y2
,size
,y_offset
,stare_at_x
,stare_at_y
: refer to the documentation forblabber:entity
Composition (blabber:group
)
Groups several illustrations together. This type can be nested as desired. Properties:
items
(type:array
): an array of illustrations that get grouped together
Here is the JSON object used to create the “conversation” in the above screenshot:
Example Illustration JSON
{
"illustrations": {
"discussion": [
{
"type": "blabber:entity",
"entity": "@interlocutor",
"x1": 0,
"y1": 80,
"x2": 100,
"y2": 180,
"size": 100,
"y_offset": 0.5,
"stare_at_x": 50,
"stare_at_y": 0
},
{
"type": "blabber:entity",
"entity": "@s",
"x1": 100,
"y1": 80,
"x2": 200,
"y2": 180,
"size": 100,
"y_offset": 0.5,
"stare_at_x": -50,
"stare_at_y": 0
}
]
}
}
This illustration can then be used in any dialogue state by adding it to its illustrations
array:
{
"states": {
"my_state": {
"text": "...",
"illustrations": [
"discussion"
]
}
}
}
Conditional choices
So what if you want to add requirements for specific dialogue paths? You could always make a separate dialogue file for each possible combination and trigger one based on prior conditions, but that becomes quite tedious when you have multiple conditions in a single dialogue, and it also does not give players any indication of what choices they may have missed.
To help with that situation, Blabber gives you the ability to lock some dialogue choices behind predicates. Here is what a locked choice may look like:
When you make a choice conditional, you specify when the choice should be available, and how it should be displayed if not. The condition is given as an identifier for a predicate.
As for the display, you can either make it so the choice is grayed out, displaying a little lock icon and explanation message when hovered, or set it to be hidden.
Here is an example of conditional choices in JSON:
Grayed out choice JSON
{
"text": "I have money.",
"next": "barter",
"only_if": {
"predicate": "testmod:holding_emerald",
"when_unavailable": {
"display": "grayed_out",
"message": "You must be holding an emerald to pick this option."
}
}
}
Hidden choice JSON
{
"text": "I have money.",
"next": "barter",
"only_if": {
"predicate": "testmod:holding_emerald",
"when_unavailable": {
"display": "hidden"
}
}
}
The full example with predicate included is available in Blabber’s test mod.
Interlocutors
Of course, dialogues often involve talking to someone (or something). Since version 1.2.0, Blabber lets you specify an interlocutor entity when starting a dialogue (using an optional argument in the command / in the API).
This relationship can be used in several ways:
In commands and texts
Blabber adds a new @interlocutor
selector, which targets the current interlocutor of the command’s source.
It only works when @s
is a player, which includes commands run from dialogue actions and commands run through execute as <player> run ...
.
Example use:
Here is how the above text may be used:
In predicates
The interlocutor entity can also be used in predicates files by using the blabber:interlocutor_properties
condition type.
This new condition type lets you apply the same checks to a player’s current interlocutor as minecraft:entity_properties
would on the player themselves.
For example:
{
"condition": "blabber:interlocutor_properties",
"predicate": {
"type": "minecraft:villager"
}
}
Online Dialogue Maker
If you are allergic to code, try Parlour! It is an online tool to create dialogues, right on this website.
Validation
To help creators design dialogues, and prevent players from getting stuck in a (possibly non-skippable) dialogue with no ending, both the online dialogue maker and the mod itself will perform several validation checks on dialogue files.
The validation process checks for the following issues and reports them by either logging a warning or failing with an error:
Errors:
- States with no choices: Every non-end state must have at least one choice leading out of it. If any state has no choices defined, an error will be thrown.
- Softlock states: Every state must have a path leading to an ending (no infinite loops). If any state is lacking a path to an end state, an error will be thrown.
Warnings:
- Conditional softlock states: Any state that only has conditional paths leading to an ending will be reported. Blabber cannot tell whether a condition will necessarily be fulfilled when getting to such a state, and thus cannot prove that the player will not be softlocked.
- Unreachable states: Any state that is disconnected from the main dialogue graph will be reported with a warning message. While they do not cause immediate issues for players, you may want to connect or remove such orphan states.
Mod Compatibility
Heracles
The Heracles quest mod can be used with the Heracles for Blabber add-on to incorporate dialogues into your modpack’s or server’s quests.
Text Animator
The Text Animator mod can be used to add special effects to your dialogues’ texts :
Using Blabber (for developers)
If you are a developer, you can use Blabber as a library for your own project by inserting the following in your build.gradle
:
You can then add the library version to your gradle.properties
file:
You can find the current version of Blabber in the releases tab of the repository on Github, and the latest CCA version in the appropriate repository.
API
The two most relevant methods are as follow:
Blabber#startDialogue(ServerPlayerEntity, Identifier)
: starts the dialogue with the given id for the given playerBlabber#registerAction
: registers an action for use in dialogues, 2 overloads available:registerAction(Identifier, DialogueAction)
: registers a simple action that takes no additional configuration from the dialogue description file.registerAction(Identifier, Codec<? extends DialogueAction)
: registers an action type. The codec is used to create new dialogue actions based on the actionvalue
specified in the dialogue description file.
Custom layouts
It is possible to register your own custom layout with its completely custom screen by calling BlabberScreenRegistry#register
in your client entrypoint. The API is however marked unstable, as the layout system is susceptible to being refactored to allow arbitrary data being passed to the screen
(contributions welcome).
JSON Schema
The schema for Blabber dialogue files is available here: dialogue.schema.json