A Minecraft Forge mod that adds a slack/discord-style chat interface for dialogues. Designed for modpack creators to script conversations via datapacks and commands.
- Slack/Discord-style UI: Sidebar with conversation list, chat history panel with message bubbles
- Team-based conversations: Players share conversation history within their team
- Datapack-driven dialogues: Define dialogue trees in JSON, loaded as datapack resources
- Action buttons: Clickable response options that trigger commands or continue dialogue
- Conditional actions: Show/hide buttons based on data, scores, or KubeJS callbacks
- Template system: Dynamic text with player names, team data, world info
- Typing indicators: Simulated typing delay before messages appear
- Toast notifications: Non-intrusive popups when new messages arrive
- Custom avatars: Load PNG images from config folder for sender portraits
- Team data storage: Store values, states, and scores per-team
- KubeJS integration: Register custom callbacks for conditions and templates
/simchat send <player> <dialogueId> - Send dialogue to player
/simchat system <player> <entityId> <message> - Send system message
/simchat clear <player> [entityId] - Clear chat history
/simchat open <player> [entityId] - Open chat screen for player
/simchat reload - Reload KubeJS callbacks
/simchat team create <name> - Create a new team
/simchat team invite [player] - Invite player (or broadcast to all if omitted)
/simchat team join <teamId> - Join a team by ID
/simchat team list - List all teams
/simchat team info - Show current team info
/simchat team title <newTitle> - Change team name
/simchat team color <color> - Change team color (name only)
Available colors: black, dark_blue, dark_green, dark_aqua, dark_red, dark_purple, gold, gray, dark_gray, blue, green, aqua, red, light_purple, yellow, white
Store values per-team for tracking progress, scores, states. All commands accept an optional [target] parameter (player name or team ID/title) to operate on a specific team:
/simchat data get <key> [target] - Get value
/simchat data set <key> <value> [target] - Set value (auto-detects numbers)
/simchat data add <key> <amount> [target] - Add to numeric value
/simchat data remove <key> [target] - Remove key
/simchat data list [target] - List all data
Examples:
/simchat data get gold - Get your team's gold
/simchat data get gold Steve - Get Steve's team's gold
/simchat data set rank vip "Team Alpha" - Set string on Team Alpha
/simchat data set gold 100 - Set number (auto-detected)
/simchat data add points 10 abc1234 - Add 10 points to team abc1234
/simchat callback list - List registered KubeJS callbacks
/simchat callback run <name> [player] - Execute callback and show result
Dialogues are loaded from: data/<namespace>/simchat/<path>.json
Example: data/mypack/simchat/contractor/greeting.json
{
"entityId": "contractor",
"entityName": "Director Vex",
"entitySubtitle": "Helion Industries",
"text": "Hello {player:name}! Your team ({team:title}) has completed {data:contracts_done} contracts.",
"actions": [
{
"label": "Accept Contract (+{data:reward} credits)",
"commands": [
"simchat data add contracts_done 1",
"give @s emerald 10"
],
"reply": "I'll take the job.",
"nextState": "mypack:contractor/contract_details",
"condition": "data:has_clearance"
},
{
"label": "Decline",
"reply": "Not interested.",
"condition": "!data:forced_contract"
}
]
}| Field | Type | Description |
|---|---|---|
entityId |
string | Unique entity identifier (used for avatar lookup and conversation grouping) |
entityName |
string | Display name shown in chat |
entitySubtitle |
string | Optional subtitle (company, title) |
text |
string | Message content (supports templates) |
actions |
array | Response buttons (optional) |
| Field | Type | Description |
|---|---|---|
label |
string | Button text (supports templates) |
commands |
array | Commands to run when clicked |
reply |
string | Player's reply shown in chat (supports templates) |
nextState |
string | Dialogue ID to trigger after this action |
condition |
string | Condition that must be true to show button |
itemsVisual |
array | Items to display on button |
itemsInput |
array | Items required from player (checked before enabling) |
itemsOutput |
array | Items given to player |
{
"item": "minecraft:diamond",
"count": 5
}Templates work in entityName, entitySubtitle, text, label, reply, and commands.
Prefix with {compile:...} (default) to resolve on the server when the message is created, or {runtime:...} to resolve on the client when the message is displayed. Runtime templates are stored and resolved client-side; the server only sees the compiled text. Runtime values refresh when the chat opens, when new messages arrive, or via the Refresh button.
Use {resolver:name} syntax in text, labels, and replies:
| Template | Description | Example |
|---|---|---|
{player:name} |
Player's username | "Steve" |
{player:uuid} |
Player's UUID | "069a79f4..." |
{team:id} |
Team ID | "a1b2c3d" |
{team:title} |
Team name | "The Builders" |
{team:memberCount} |
Number of team members | "3" |
{team:color} |
Team color name | "dark_blue" |
{data:keyname} |
Team data value | "42" |
{world:day} |
Current world day | "15" |
{world:time} |
Time of day (0-24000) | "6000" |
{world:dimension} |
Dimension ID | "minecraft:overworld" |
{world:weather} |
Weather state | "clear", "rain", "thunder" |
{kjs:callbackName} |
KubeJS callback result | (any value) |
Example:
{
"text": "Day {world:day}: Hello {player:name}! You have {data:points} points."
}Use conditions to show/hide action buttons. Prefix with ! to negate.
| Condition | Description |
|---|---|
data:keyname |
True if team data is truthy (exists, non-zero, non-empty) |
kjs:callbackName |
True if KubeJS callback returns truthy |
score:objectiveName |
True if player's scoreboard score > 0 |
permission:level |
True if player has permission level |
Examples:
{
"actions": [
{
"label": "VIP Option",
"condition": "data:is_vip"
},
{
"label": "Regular Option",
"condition": "!data:is_vip"
},
{
"label": "Admin Only",
"condition": "permission:2"
}
]
}Register callbacks in kubejs/server_scripts/simchat.js:
// Clear old callbacks on reload
SimChat.clearCallbacks()
// Register a condition callback
SimChat.registerCallback('hasEnoughGold', ctx => {
return ctx.player.persistentData.getInt('gold') >= 100
})
// Register a template callback
SimChat.registerCallback('goldAmount', ctx => {
return ctx.player.persistentData.getInt('gold')
})
// Register using team data
SimChat.registerCallback('isVeteran', ctx => {
return ctx.team && ctx.team.data.missions_completed >= 10
})
// Time-based callback
SimChat.registerCallback('greeting', ctx => {
let time = ctx.player.level.dayTime % 24000
if (time < 6000) return 'Good morning'
if (time < 12000) return 'Good afternoon'
return 'Good evening'
})
SimChat.logStatus() // Log callback countAvailable in callbacks via ctx:
// Player (KubeJS wrapped - full access)
ctx.player
ctx.player.persistentData
ctx.player.level.dayTime
ctx.player.inventory
// Team (null if no team)
ctx.team.id
ctx.team.title
ctx.team.memberCount
ctx.team.data // Map of all team data
ctx.team.data.keyname // Access specific key
ctx.team.hasData('key') // Boolean check
// Entity (null if no entity context)
ctx.entity.id
ctx.entity.displayName
ctx.entity.messageCount
ctx.entity.lastMessage
ctx.entity.isTyping{
"text": "{kjs:greeting}, {player:name}! You have {kjs:goldAmount} gold.",
"actions": [
{
"label": "Buy Item (100 gold)",
"condition": "kjs:hasEnoughGold",
"commands": ["simchat data add purchases 1"]
}
]
}Place entity configs and avatars in: config/simchat/entities/
Each entity can have:
<entityId>.json- Config with name, subtitle, avatar settings<entityId>.png- Avatar image (any size, displayed at 36x36)
Example: config/simchat/entities/merchant.json
{
"name": "Merchant Bob",
"subtitle": "Ironwood Trading Co.",
"avatar": "merchant"
}| Field | Description |
|---|---|
name |
Default display name |
subtitle |
Default subtitle |
avatar |
Avatar ID (defaults to entityId) |
Create default.json and/or default.png as fallbacks for entities without specific files.
All entity files hot-reload when modified.
| Option | Default | Description |
|---|---|---|
notificationSound |
minecraft:block.note_block.bell |
Sound on new message |
notificationVolume |
0.5 |
Sound volume (0.0-1.0) |
showToasts |
true |
Show toast popups |
toastDuration |
5.0 |
Toast display time (seconds) |
sidebarWidth |
240 |
Conversation list width |
sidebarSortMode |
0 |
Sort: 0=recent, 1=alphabetical |
| Option | Default | Description |
|---|---|---|
minDelay |
0.3 |
Minimum typing delay (seconds) |
maxDelay |
3.0 |
Maximum typing delay (seconds) |
charsPerSecond |
100.0 |
Simulated typing speed |
commandPermissionLevel |
2 |
Permission for /simchat commands |
| Key | Action |
|---|---|
; (semicolon) |
Open chat screen |
Validate your dialogues with the JSON schema at schemas/dialogue.schema.json.
VS Code setup:
{
"$schema": "https://raw.githubusercontent.com/YardenZamir/sim-chat/main/schemas/dialogue.schema.json",
"entityId": "...",
...
}MIT