This lightweight mod adds structured, timed messages to chat: create monologues with precise WPM timing and line-by-line delivery!
ChatDiag's dialogs can be provided by datapacks, mod integration, and command blocks. They are specially designed for storytelling in server events and mapmaking.
Dialogs support formatting codes, as well as modded sounds and commands.
Executing dialogs
To start rendering a dialog, use the new /chatdiag or /cdiag admin command.
Syntax
Executes a defined dialog by namespace
/chatdiag [players] id [dialog-id]
Example:
/chatdiag @s id example:example_dialog

Executes a defined dialog by data
/chatdiag [players] data [dialog-object]
Example:
/chatdiag @a data {"prefix": "<ChatDiag> ", "lines": ["Hello!", "This dialog was not defined in any file."]}

Development
Data packs
Data-driven dialogs are defined via namespaced resources. These definitions must reside under the chatdiag/ directory (data/<namespace>/chatdiag/<file>.json, loads as <namespace>:<file>) for mod resources or datapacks.
/reload reloads data-pack dialogs.
Mod integration
ChatDiag provides the ChatDiag.api() integration entrypoint for mods.
Dialogs can be made to keep the same completable future across chained dialogs, so the result only completes once the entire chain is done.
In order to declare a dependency on ChatDiag from your mod, add the following to your build.gradle:
repositories {
// ...
maven { url = "" rel="noopener nofollow" target="_blank">https://api.modrinth.com/maven" }
}
dependencies {
// ...
// chatdiag_version example: 1.0.0+1.21.11
modImplementation "maven.modrinth:chatdiag:${project.chatdiag_version}"
}
Dialog definition
Dialogs
Dialogs consist of a list of Lines, and optional settings that add custom behaviors. These behaviors are:
- WPM. Words per minute. Controls delay for each line. Defaults to 120, must be positive.
- Prefix. Renders before each line.
- Suffix. Renders after each line.
- Sounds. Can be either a single entry or an array. Plays for each line.
- Next dialog. Used to chain dialogs together. Must be a namespaced dialog identifier. After the given dialog ends, the next one will start.
- Next command. Must be a valid Minecraft/mod command. Executes at the end of the current dialog. Commands that are run via dialogs inherit their source's permissions. Because of this, someone could run some mischievous commands with them if executing from a datapack, so please make sure you understand what dialogs you're executing and not running shared dialogs blindly. Beware!
Dialog lines can be either:
- A string with their dialog's behavior, or
- A DialogLine object with custom behavior. Defined custom behaviors are able to override or add to their dialog's settings.
A DialogLine object can replace its parent dialog's behaviors via its replace_prefix, replace_suffix, and replace_sound boolean flags.
Moreover, DialogLines can execute commands using their command attribute. This is different from Dialogs' next_command, as command runs when rendering, and next_command runs after the last line's delay has passed.
Sound objects contain a namespaced sound Id, and the following optional attributes:
- Pitch. Defaults to 1. Ranges between
0.5and2.0. - Volume. Defaults to 1. Must be positive.
- Position. Defaults to every player's client. Can be a list or a single entry. Each entry is defined as a vector or a string describing an entity selector. This is specially useful for arbitrary positions, as one can use marker entities.
If a player does not have ChatDiag installed, sounds with an unspecified position will simply play at each player's position. Therefore, if a players moves, the sound will be localized to where they were standing when the sound started playing (just like with the
/plasoundcommand). Because of this, having ChatDiag on both the server AND the client is recommended, but not needed.
Dialog definition example
{
"wpm": "number",
"sound": {
"id": "string",
"pitch": "number"
},
"prefix": "string",
"suffix": "string",
"lines": [
"string",
{
"line": "string",
"replace_sound": "boolean",
"replace_prefix": "boolean",
"replace_suffix": "boolean",
"sound": [
{
"id": "string",
"pitch": "number",
"position": "string"
},
{
"id": "string",
position: [
["number", "number", "number"],
"string",
"string"
]
}
],
"prefix": "string",
"suffix": "string",
"delay": "number",
"command": "string"
}
],
"next_command": "string",
"next_dialog": "string",
}
Dev Tips
- When dealing with dialog chains and branches, it's generally better to make use of folder structure. For instance,
example:entity/mission/successandexample:entity/welcome/0are superior toexample:entity_mission_successandexample:entity_welcome_startin most cases where you have multiple entity and mission dialogs. - Don't invoke new dialogs in
next_commandattributes. If you want to begin a dialog immediately after another without waiting for the last line's delay, you can instead turn the last line into a DialogLine object and specify"delay": 0. - When specifying sound positions, it's advised not to use datapack macros. If a value does not change, it's better for it to be in a vector position. If not, entity selectors with marker entities tend to be more flexible.
Feel free to use this mod in your modpacks!