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.
/blabber settings set <setting> <true|false>
: Toggles a debug setting.<setting>
: the name of a debug setting - currently, the only possible value isdebug.anchors
.
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).
Starting in version 1.6.0, layouts can take additional parameters to customize their render.
Currently (1.6.0), the only supported parameter is main_text_margins
on the blabber:rpg
layout.
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"
}
}
Parameterized layout JSON
{
"layout": {
"type": "blabber:rpg",
"params": {
"main_text_margins": {
"left": 52,
"right": -4,
"top": 10,
"bottom": 5
}
}
}
}
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.
Positioning Illustrations
Illustrations are positioned on the screen by setting their x
and y
coordinates, in âlogical pixelsâ.
By default, coordinates start at (0, 0)
in the top-left corner of the screen, and increase towards the bottom-right corner of the screen.
To help you position your illustrations, Blabber provides several anchors other than the windowâs top-left corner.
When using a specific anchor, coordinates are translated such that (0, 0)
is the position of the anchor itself.
Available anchors are currently as follows:
- Generic anchors: When using these anchors, general illustrations are positioned relative to a point of the window,
while illustrations attached to specific choices are positioned relative to the choiceâs
text (which is notably useful to keep up with localization shifting those around).
top_left
(the default)top_right
bottom_left
bottom_right
center
- Specific anchors: the position of these anchors is dictated by the layout. Some layouts may not support them at all.
before_main_text
: matches the top-left corner of the main textbox for a given layout.spot_1
,spot_2
: arbitrary positions that are considered âgood spotsâ for an illustration in the current layout. The exact position of these spots for each default layout is not yet set in stone - feedback welcome.
To better visualize the position of each anchor, you can enable the relevant debug mode.
Illustration Types
There are currently 3 types of illustrations, plus the group type:
Item (blabber:item
)
Renders an item stack with optional NBT, as if within an inventory slot. Properties:
item
(type:item stack
): the data for the item to renderanchor
(type:IllustrationAnchor
): the point of the screen relative to which thex
andy
coordinates are computed. By default, will be the top-left corner of the screen.x
(type:integer
): theX
coordinate of the top-left corner for the drawn itemy
(type:integer
): theY
coordinate of the top-left corner for the drawn itemscale
(type:float
, optional) >1.6.0: the size of the rendered item will be multiplied by this amount. By default, the item will be drawn at the same size as within an inventory slot.show_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.anchor
(type:IllustrationAnchor
): the point of the screen relative to which thex
andy
coordinates are computed. By default, will be the top-left corner of the screen.x
(type:integer
): theX
coordinate of the frameâs upper left cornery
(type:integer
): theY
coordinate of the frameâs upper left cornerwidth
(type:integer
): the width of the frame, in logical pixelsheight
(type:integer
): the height of the frame, in logical pixelsentity_size
(type:integer
): the size of the entity within the frame (values should stay within the ballpark of the frameâs width/height)y_offset
(type:decimal number
): how far down the entity should be pushed within the framestare_at
(type:object
)anchor
(type:IllustrationAnchor
, optional): the point of the screen relative to which thex
andy
coordinates are computed. If left unspecified, will be the entity frameâs center.x
(type:integer
, optional): theX
coordinate, relative to theanchor
, towards which the entity should look. If left unspecified, the entityâs stare will horizontally follow the playerâs cursor.y
(type:integer
, optional): theY
coordinate, relative to theanchor
, 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 entityanchor
,x
,y
,width
,height
,entity_size
,y_offset
,stare_at
: refer to the documentation forblabber:entity
Fake Player (blabber:fake_player
) >1.6.0
Just like blabber:entity
, but renders a fake player with the desired profile, with optional NBT. Properties:
profile
(type:object
): the full profile of the player. You can get it using this tool.id
(type:string
): the UUID of the player, without dashesname
(type:string
): the name of the player - does not have to match the real playerâs nameproperties
(type:array
): additional properties, most relevant of which is the encoded player skin and the associated signature. Blabber will not be able to render the right skin without a valid value here.
data
(type:object
, optional): NBT data to apply to the rendered entitymodel_customization
(type:object
): options for the player modelmain_hand
(type:string
, optional): set to"left"
to render the fake player as left-handed. Defaults to"right"
.visible_parts
(type:array
, optional): a list that can contain the values"cape"
,"jacket"
"left_sleeve"
,"right_sleeve"
,"left_pants_leg"
,"right_pants_leg"
, and"hat"
. Parts that are not in this list will be hidden. By default, all parts are visible.
anchor
,x
,y
,width
,height
,entity_size
,y_offset
,stare_at
: refer to the documentation forblabber:entity
Texture (blabber:texture
) >1.6.0
Renders a rectangular texture or an area thereof. The texture can come from the base game, a mod, or a resourcepack that clients have installed.
Textures may be animated using a pack.mcmeta
file. Properties:
texture
(type:string
): the ID of the texture in the format<namespace>:<path>
, where<path>
is the path of the PNG image relative to theassets
directory (extension included)anchor
(type:IllustrationAnchor
): the point of the screen relative to which thex
andy
coordinates are computed. By default, will be the top-left corner of the screen.x
(type:integer
): theX
coordinate of the drawn areaâs upper left cornery
(type:integer
): theY
coordinate of the drawn areaâs upper left cornerwidth
(type:integer
): the width of the drawn area, in logical pixelsheight
(type:integer
): the height of the drawn area, in logical pixels
The following properties are optional and allow you to draw a specific region of a texture file:
u
(type:integer
, optional): theX
coordinate of the upper left corner in the texture file, in real pixels (defaults to 0)v
(type:integer
, optional): theY
coordinate of the upper left corner in the texture file, in real pixels (defaults to 0)textureWidth
(type:integer
, optional): the actual width of the texture file, in real pixels (defaults towidth
)textureHeight
(type:integer
, optional): the actual height of the texture file, in real pixels (defaults toheight
)regionWidth
(type:integer
, optional): the width of the region to draw from the file, in real pixels (defaults towidth
)regionHeight
(type:integer
, optional): the height of the region to draw from the file, in real pixels (defaults toheight
)
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.
- Nonexistent illustrations: Illustrations must be defined in the appropriate section before getting referenced in a state. If any state is referencing an inexistant illustration, an error will be thrown.
- Invalid illustrated states: Only regular dialogue states are allowed to have illustrations. If any confirmation or end state is using illustrations, 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.
Debug Modes
Blabber ships with a debug feature for dialogue screens, which can be enabled using the /blabber settings
command.
Currently, the only debug mode available is debug.anchors
, which displays the position of anchors, as well as the position of the cursor
relative to each anchor.
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 :
Taterzens
The Taterzens mod can be used to create NPCs that can trigger Blabber dialogues when interacted with.
FAQ
Q: (Neo)Forge?
A: I do not wish to spend development time supporting Forge. However, on 1.20.1, you can use the Sinytra Connector mod to make Blabber run regardless. If you are a mod developer who wishes to provide support for another loader, you can get in touch with us on our Discord server.
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 buildscript :
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 both Blabber#registerLayout
in your main entrypoint and
BlabberScreenRegistry#register
in your client entrypoint. The API is currently marked as experimental, so some refactors may happen in future updates.
Custom illustrations
It is possible to register entirely custom illustrations by calling both Blabber#registerIllustration
in your main entrypoint and
DialogueIllustrationRenderer#register
in your client entrypoint. The API is currently marked as experimental, so some refactors may happen in future updates.
JSON Schema
The schema for Blabber dialogue files is available here: dialogue.schema.json