▶️ ЗАБЕРИ СВОИ 8 ПОДАРКОВ 🎁 ПРИ СОЗДАНИИ СВОЕГО МАЙНКРАФТ СЕРВЕРА
hChat

hChat

A modern and complete chat system for Paper 1.18+ servers.

Оцените первым
55
4

hChat — A modern and complete chat system for Paper 1.18+ servers.
Chat channels, direct messages, mentions, moderation (slowmode, chatlock, filters), AFK, staff chat, mail, replay, and more.

FeaturesQuick StartCommandsPermissionsConfigurationLocalizationPlaceholdersDependenciesBuildingContributing


📋 Table of Contents
  • ✨ Features
  • ⚡ Quick Start
  • 🎮 Commands
  • 🔒 Permissions
  • ⚙️ Configuration
  • 📡 Chat Channels
  • 🌐 Localization
  • 🔌 Placeholders
  • 🛡️ Filters
  • 📦 Broadcasts
  • 📨 Mail (Offline Messages)
  • 😴 AFK
  • 🔌 Developer API
  • 🌐 Proxy note
  • 🧩 Dependencies
  • 🛠️ Building from Source
  • 🤝 Contributing
  • 📄 License

✨ Features

💬 Direct Messages
Customizable format with hover tooltips and click-to-reply
🔔 @Mentions
Configurable sound, highlight color, and personal notification
👁️ Spy Mode
Monitor private messages with a dedicated permission
🚫 Ignore System
Persistent per-player block list that survives reloads
🌍 Multi-language
YAML localization, including per-player language selection
🔗 PlaceholderAPI
%hchat_spy_enabled%, %hchat_ignored%, DND, last seen…
🎨 Hex Colors
&#RRGGBB hex + classic & legacy codes
🖱️ Hover & Click
Tooltips and clickable actions on every chat line
📦 Broadcasts
Manual /bc plus auto-broadcast scheduler
🛡️ Moderation
Slowmode, chat lock and staff chat (/sc)
🔤 Filter Chain
Word filter + anti-caps, anti-unicode, anti-ad, anti-spam
📜 Chat Logger
Rotating daily logs with configurable retention
📡 Chat Channels
Per-world, per-permission, aliases, cooldowns
📬 Mail
Offline messages with /hchat mail read|clear|send
😴 AFK
Automatic inactivity detection + /afk [message]
📢 Mass Mentions
@everyone / @here with cooldown + sound
⏱️ Ping & Seen
/ping [player] and /seen <player>
🔄 Chat Replay
/hchat replay [player] on a ring buffer

⚡ Quick Start

📥 Installation

# 1. Download the latest JAR from Releases
wget https://github.com/hauchdev/hChat/releases/latest/download/hChat.jar

# 2. Drop it into your server's plugins folder
mv hChat.jar /your-server/plugins/

# 3. Make sure PlaceholderAPI and LuckPerms are installed (required)

# 4. Restart or reload your server

hChat generates plugins/hChat/config.yml and plugins/hChat/lang/lang_en.yml on first start. Edit them, then run /hchat reload.


🎮 Commands

CommandAliasesDescriptionPermission
/message <player> <message>/msg, /tell, /w, /m, /whisperSend a private messagehchat.message
/reply <message>/rReply to the most recent private messagehchat.reply
/broadcast <message>/bcBroadcast a message to the whole serverhchat.broadcast
/ignore <player>Toggle ignoring a specific playerhchat.ignore
/ignore listList ignored players (click to unignore)hchat.ignore
/spyToggle spy mode (see all private messages)hchat.spy
/clearClear the chat of every playerhchat.clear
/channel [name]/chList or switch your active chat channelhchat.channel
/slowmode <seconds|off|status>Global chat slowmode (in-memory, bypassable)hchat.slowmode
/chatlock <on|off|status>Lock / unlock the whole chathchat.chatlock
/sc <message>Staff-only chat channelhchat.sc
/dnd [on|off]Toggle do-not-disturb (blocks incoming DMs)hchat.dnd
/ping [player]Show your (or someone else's) latencyhchat.ping
/seen <player>When the player last sent you a messagehchat.seen
/afk [message]Toggle AFK (auto-detected after inactivity too)hchat.afk
/hchat reloadReload config.yml and language fileshchat.reload
/hchat helpShow the in-game help menuhchat.help
/hchat lang <lang>Switch your own player languagehchat.lang
/hchat aboutVersion, authors and feature overviewhchat.help
/hchat mail <read|clear|send>Read / clear / send offline messageshchat.help
/hchat replay [player]Reprint recent chat (optionally filtered by player)hchat.help
/hchat replay clear-bufferEmpty the replay bufferhchat.clear

⌨️ Tab completion — every command supports it where it makes sense: /hchat completes its subcommands (reload, help, lang, update, filtered by permission) and /hchat lang completes the language codes from lang/; /message and /ignore complete online player names (/message also suggests offline players, since it can deliver offline messages); /channel completes the configured channel ids.


🔒 Permissions

PermissionDefaultDescription
hchat.*opAccess to every hChat command and feature
hchat.messagetrueAllows /msg, /tell, /w, /m, /whisper
hchat.replytrueAllows /reply, /r
hchat.broadcastopAllows /broadcast, /bc
hchat.broadcast.coloropAllows color codes inside broadcast messages
hchat.ignoretrueAllows /ignore <player>
hchat.spyopAllows toggling /spy
hchat.spy.allopReceive every private message without exception
hchat.clearopAllows /clear
hchat.reloadopAllows /hchat reload
hchat.helptrueAllows /hchat help
hchat.langtrueAllows /hchat lang <lang>
hchat.channeltrueAllows /channel and channel switching
hchat.slowmodeopAllows /slowmode
hchat.slowmode.bypassopBypass the global chat slowmode
hchat.chatlockopAllows /chatlock
hchat.chatlock.bypassopKeep talking while the chat is locked
hchat.scopAllows /sc staff chat
hchat.dndtrueAllows /dnd
hchat.bypass.dndopSend DMs to players with DND enabled
hchat.pingtrueAllows /ping
hchat.ping.othersopAllows /ping <player>
hchat.seentrueAllows /seen
hchat.afktrueAllows /afk
hchat.mention.everyoneopAllows using @everyone
hchat.mention.hereopAllows using @here
hchat.monitor.filteropReceive warnings when the word filter trips on a player
hchat.bypass-logopSend private messages without writing them to the chat logger

⚙️ Configuration

config.yml is generated automatically on first start. The same file also controls every audio / visual cue the plugin emits.

📄 View full config.yml
# config-version is bumped automatically when new options are added;
# your settings are always kept (old file backed up as
# config-backup-v{n}.yml).
config-version: 7

lang: en
debug: false

update-checker:
  enabled: true
  notify-admins: true

chat:
  default-format: "&7%luckperms_prefix% {player} %luckperms_suffix%&8: &f{message}"
  hex-colors: true
  formats:
    vip:
      permission: hchat.chat.format.vip
      format: "&6&lVIP &8» &e{prefix}{player}{suffix} &8: &f{message}"
    mvp:
      permission: hchat.chat.format.mvp
      format: "&b&lMVP &8» &b{prefix}{player}{suffix} &8: &7{message}"
    admin:
      permission: hchat.chat.format.admin
      format: "&c&lADMIN &8» &c{prefix}{player}{suffix} &8: &7{message}"

# Dynamic chat tokens: [ping] [item] [coords] [world] [afk]
placeholders:
  ping:
    enabled: true
    symbol: "▪"
    show-value: true
    value-suffix: "ms"
    good-max: 80
    medium-max: 150
    good-color: "&a"
    medium-color: "&e"
    bad-color: "&c"
    value-color: "&7"
  item:
    enabled: true
  coords:
    enabled: true
    format: "&7({x}, {y}, {z})"
  world:
    enabled: true
    format: "&7{world}"
  afk:
    enabled: true
    placeholder: "%essentials_afk%"
    afk-values: ["yes", "true"]
    format: "&c[AFK]&r "

welcome:
  enabled: true
  message: "&a&lWelcome &e{player} &a&lto the server!"
  hide-vanilla: true
  motd-on-join: false
  sound:
    enabled: true
    sound: "entity.player.levelup"
    volume: 0.6
    pitch: 1.0
  first-join:
    enabled: true
    message: "&6&l★ &e{player} &6just joined for the first time!"
    hide-vanilla: true

quit:
  enabled: true
  message: "&c{player} &7left the server."
  hide-vanilla: true

mentions:
  sound:
    enabled: true
    sound: "entity.experience_orb.pickup"
    volume: 1.0
    pitch: 1.0
  colors:
    enabled: true
    color: "&#54A3FF"
  # Bold highlight (a real background color is not possible in chat).
  highlight: true
  everyone-permission: hchat.mention.everyone
  here-permission: hchat.mention.here
  everyone-cooldown-seconds: 60
  everyone-sound:
    enabled: true
    sound: "entity.wither.spawn"
    volume: 1.0
    pitch: 1.0

direct-messages:
  sender:
    format: "&7[&eYou &7-> &e{receiver}&7] &7{message}"
    hover-text:
      enabled: false
  receiver:
    format: "&7[&e{sender} &7-> &eYou&7] &7{message}"
    hover-text:
      enabled: true
  clickable-actions:
    enabled: true
    reply-command: "/msg {sender}"
  silenced-action-bar:
    enabled: true
    text: "&e{receiver} is muted - the message was not delivered."

spy-format: "&e{sender} &7-> &e{target}&7: &7{message}"

hover-text: enabled: true format: - "&#54FF7F %player_name%" - "&7" - "&eClick to send a private message"

channels: default-by-permission: - permission: hchat.channel.default.vip channel: vip hint-on-switch: true hint-on-join: true global: range: -1 local: format: "&8[Local] &7{player} &8» &f{message}" range: 80 action-bar-hint: "&eThere are people talking near you" alias: "#l" staff: format: "&c[Staff] {player} &8» &f{message}" speak-permission: hchat.channel.staff see-permission: hchat.channel.staff.see alias: "#staff" vip: format: "&e[VIP] {player} &8» &f{message}" speak-permission: hchat.chat.format.vip alias: "#vip" trade: format: "&6[Trade] {player} &8» &f{message}" cooldown-ms: 5000 alias: "#trade" world: format: "&7[{world}] {player} &8» &f{message}" range: -1 per-world: true alias: "#world"

broadcast: enabled: true cooldown-ms: 0 format: - "" - "&#2791F5Broadcast:" - "{message}" example1: enabled: true message: "&#F52727This broadcast sent every 10 minutes. Edit in /hChat/config.yml" interval: 600 display-in-console: true

offline-messages: max-pending: 10 sound: enabled: true sound: "entity.experience_orb.pickup" volume: 1.0 pitch: 1.0

logging: private-messages: enabled: true path: logs retention-days: 30

word-filter: enabled: true words: ["blacklist1", "blacklist2"] action: "block" # block | mask | warn

Advanced filters (config v6): anti-caps, anti-unicode, anti-ad,

anti-spam - see the "Filters" section below.

filters: anti-caps: enabled: true max-uppercase-percent: 70 min-length: 8 action: "mask" anti-unicode: enabled: true block-invisible: true action: "block" anti-ad: enabled: true patterns: - "(?<![a-zA-Z0-9])([a-z0-9-]+\.)+(com|net|org|gg|io)" - "(discord\.gg/|discordapp\.com/invite/)" sensitivity: medium whitelist: - "tu-servidor.com" - "discord.gg/tuinvite" action: "warn" anti-spam: enabled: true global-cooldown-ms: 1500 flood: max-messages: 5 window-seconds: 3 similarity-threshold: 0.8 action: "block"

replay: capacity: 50

afk: enabled: true auto-timeout-seconds: 300 check-interval-seconds: 30 unset-on-activity: true notify-unset: true

slowmode: enabled: true seconds: 3 bypass-permission: hchat.slowmode.bypass

chat-lock: enabled: true bypass-permission: hchat.chatlock.bypass

staff-chat: format: "&c[Staff] {player} &8» &f{message}" log-to-console: true

death-message: enabled: true format: "&c☠ &7{player} &fdied by {cause}" custom: FALL: "&c{player} learned to fly." LAVA: "&c{player} made friends with the magma."


</details>

### 🔁 Available placeholders

| Placeholder     | Replaced with                                          |
|-----------------|--------------------------------------------------------|
| `{sender}`      | Sender's display name                                  |
| `{receiver}`    | Recipient's display name                               |
| `{target}`      | Target name (spy view)                                 |
| `{message}`     | The actual message body                                |
| `{player}`      | Player name (mentions, offline messages, etc.)        |
| `%player_name%` | Resolved by PlaceholderAPI for any hook registered on it|

The renderer resolves every entry in two passes: first placeholders are
substituted, then `MessageFormatter` parses `&`-color codes and hex
(`&#RRGGBB`) so styling works everywhere.

#### 🎯 Dynamic chat tokens

hChat renders the following NoNChat-style tokens itself, inside every chat
format (default format, `chat.formats.*` and channel formats):

| Token      | Replaced with                                                    |
|------------|------------------------------------------------------------------|
| `[ping]`   | Colored latency indicator (green ≤ `good-max`, yellow ≤ `medium-max`, red above) with optional `ms` value |
| `[item]`   | Main-hand item; hover shows a tooltip with name, enchantments, durability bar and lore |
| `[coords]` | Player position as `x, y, z`                                     |
| `[world]`  | Current world name                                               |
| `[afk]`    | `[AFK]` prefix when the player is away (built-in `/afk` + inactivity detection, PAPI fallback) |

Example format: `"[ping] [afk]&7{player}&8: &f{message}"`. Each token
can be enabled/disabled and tuned under the `placeholders:` section of
`config.yml` (ping colors/thresholds, coords/world formats, the AFK
placeholder and its `afk-values`). Tokens are resolved at the `Component`
level after PAPI, so a literal `[ping]` typed by a player is never
turned into an indicator.

---

## 📡 Chat Channels

Channels give every conversation its own format, visibility range,
permissions and cooldown. Ship config includes `global`, `local`
(distance-based), `staff`, `vip`, `trade` and `world` (per-world).

| Feature | Where |
|---------|-------|
| Channel format, range, cooldown, aliases | `channels.<id>.*` |
| Speak / see permissions | `speak-permission`, `see-permission` |
| Distance-based local chat + action-bar hint | `range`, `action-bar-hint` |
| Per-world channel (never crosses worlds) | `per-world: true` + `{world}` |
| Auto-join by permission on entry | `default-by-permission` |
| Action-bar hint on switch / join | `hint-on-switch`, `hint-on-join` |

```yaml
channels:
  local:
    format: "&8[Local] &7{player} &8» &f{message}"
    range: 80
    action-bar-hint: "&eThere are people talking near you"
    alias: "#l"
  staff:
    format: "&c[Staff] {player} &8» &f{message}"
    speak-permission: hchat.channel.staff
    see-permission: hchat.channel.staff.see
    alias: "#staff"

In game: /channel lists channels (click to switch), /channel <name> switches your active channel (remembered between sessions) and #staff hello sends to a channel from anywhere. The default channel (global) uses chat.default-format / the permission-based chat.formats (vip/mvp/admin).


🌐 Localization

Language files live in plugins/hChat/lang/. The plugin ships lang_en.yml and supports any number of additional files.

# lang_es.yml
no-permission: "&cYou do not have permission!"
player-only: "&cOnly players can use this command!"
player-offline: "&cPlayer is offline!"
mentioned: "&#ffffffYou were mentioned in chat by &#84FFB8{player}!"

Switch the server-wide language from config.yml:

lang: es

Each player can also override their own language with /hchat lang <lang> (stored in plugins/hChat/storage/player-lang.yml). At runtime, messages are looked up in the per-player file first and fall back to the server-wide lang setting from config.yml when the key is missing or the player has not chosen a language.


🔌 Placeholders

When PlaceholderAPI is installed, hChat registers the placeholders listed below.

PlaceholderDescription
%hchat_spy_enabled%Spy Mode: Enabled / Spy Mode: Disabled
%hchat_ignored%You are ignoring players / You are not ignoring anyone
%hchat_ignored_<name>%Per-player ignore check (true / false, case-insensitive)
%hchat_ignored_count%Number of players this player is currently ignoring
%hchat_dnd_enabled%DND: Enabled / DND: Disabled
%hchat_last_sender%Name of the player who most recently sent you a private message
%hchat_last_message_part%First 30 characters (with ellipsis) of the last private message you received
%hchat_last_seen%Received N minutes ago / No recent messages

Any placeholder that resolves against a player who is currently offline returns the safe (no-player) phrasing defined in lang_en.yml.


🛡️ Filters

Every chat message runs through a filter chain in this order: word-filteranti-unicodeanti-capsanti-adanti-spam. Each filter supports the same actions:

ActionBehavior
blockDrops the message and notifies the sender with message-filtered.
maskReplaces the offending part with *, then forwards the message.
warnLets the message through and pings every player with hchat.monitor.filter.
lowercaseTransforms the message to lowercase (anti-caps).

Word filter

word-filter:
  enabled: true
  words:
    - "blacklist1"
    - "blacklist2"
  action: "block"   # block | mask | warn

Anti-caps

Blocks / masks / lowercases messages that are mostly uppercase (max-uppercase-percent, min-length).

Anti-unicode

Blocks invisible characters used to bypass filters: zero-width spaces, direction overrides, BOM, tag characters (U+E0000+) and soft hyphens.

Anti-advertisement

Matches URLs and Discord invites with configurable regex patterns plus a whitelist (substring match) that always passes.

filters:
  anti-ad:
    enabled: true
    patterns:
      - "(?<![a-zA-Z0-9])([a-z0-9-]+\\.)+(com|net|org|gg|io)"
      - "(discord\\.gg/|discordapp\\.com/invite/)"
    whitelist:
      - "tu-servidor.com"
    action: "warn"

ℹ️ The default TLD list omits me on purpose — help.me would false-positive on normal prose.

Anti-spam

A global per-player cooldown (global-cooldown-ms) plus flood detection: more than max-messages within window-seconds, or a near-identical repeat (similarity-threshold), are blocked.

filters:
  anti-spam:
    enabled: true
    global-cooldown-ms: 1500
    flood:
      max-messages: 5
      window-seconds: 3
      similarity-threshold: 0.8
    action: "block"

📦 Broadcasts

/broadcast <message> (alias /bc) shows a configurable multi-line broadcast to every player on the server. The format is set under broadcast.format in config.yml and supports placeholders plus hex colors. Players with hchat.broadcast.color can use color codes inside the broadcast body.

For scheduled announcements, drop additional entries under broadcast.<id> with enabled, message, interval (in seconds) and display-in-console:

broadcast:
  example1:
    enabled: true
    message: "&#F52727This is a recurring broadcast every 10 minutes"
    interval: 600
    display-in-console: true

The scheduler is implemented in AutoBroadcastManager.

ℹ️ Discord bridge: when DiscordSRV is installed at startup, hChat logs a confirmation and reserves the integration for the upcoming cross-server chat bridge (Phase 5 in ROADMAP.md). No broadcast or /msg is currently relayed to Discord.


📨 Mail (Offline Messages)

If a player runs /msg Steve hola while Steve is offline, the message is stored with the sender name and timestamp in OfflineMessageStore (capped at offline-messages.max-pending per recipient). When Steve logs in he sees a clickable summary — &eYou have 3 pending messages. Click to read. — instead of automatic delivery:

CommandWhat it does
/hchat mail readLists every pending message (click to reply)
/hchat mail clearPurges your own pending messages
/hchat mail send <p> <msg>Shortcut for /msg

Messages are only removed when read or cleared, and a sound plays on join if offline-messages.sound.enabled: true. If the target has never joined the server (hasPlayedBefore() == false), /msg falls back to the standard player-not-found message.


😴 AFK

hChat has a built-in AFK system — no Essentials needed:

  • /afk toggles it; /afk <message> goes AFK with a reason.
  • After afk.auto-timeout-seconds (default 300) of inactivity, players are marked AFK automatically.
  • Any real activity (movement, chat, commands, interactions) removes the state (afk.unset-on-activity); returning players are announced in chat (afk.notify-unset).
  • The [afk] chat token uses this state (with a PAPI fallback when the built-in feature is disabled).

🔌 Developer API

HChatProvider is the public entry point for other plugins. Get the singleton, then use its accessors:

import dev.hauch.hchat.api.HChatProvider;
import dev.hauch.hchat.model.ChatChannel;

public class MyListener implements Listener {

    public void demo() {
        HChatProvider api = HChatProvider.get();

        // who is spying right now
        for (java.util.UUID uuid : api.spyManager().getSpies()) {
            // ...
        }

        // last private message received by a player
        api.messageHistory().getLastMessage(player.getUniqueId());

        // the player's active channel
        ChatChannel channel = api.channelManager().activeChannel(player);

        // broadcast through an existing channel (staff, vip, ...),
        // honoring its see-permission
        api.publishToChannel(api.channelManager().get("staff"),
                "Server restarting in 5 minutes!");

        // DND state
        api.dndManager().isDnd(player);
    }
}

ℹ️ HChatProvider.get() throws IllegalStateException before the plugin is fully initialized (first ticks). Access it from ServerLoadEvent or later. Other plugins depending on hChat should declare it as a softdepend (or depend) in their plugin.yml.


🌐 Proxy note (Velocity / BungeeCord)

hChat runs inside the backend servers, not on the proxy:

  • Player#getUniqueId and %player_name% keep working behind Velocity and BungeeCord — Paper forwards the real UUID and name to the backend.
  • Private messages, offline messages, ignore and DND state are per backend server. A player connected to server A cannot /msg a player on server B; for cross-server chat use a proxy-side solution or the DiscordSRV bridge.
  • {world} and [coords] placeholders resolve on the backend the player is currently on.
  • The update checker, bStats and the auto-broadcast scheduler run once per backend instance — disable auto-broadcast on all but one server if you run a network and do not want duplicated announcements.

🧩 Dependencies

✅ Required

PluginVersionPurpose
Paper1.20+Server API (Adventure, AsyncChatEvent)
PlaceholderAPI2.11+Placeholders, Vault/LuckPerms bridge
LuckPerms5.4+Permission management

🟡 Optional (softdepend)

PluginPurpose
VaultEconomy + chat formatting hook
DiscordSRVDetected at startup; full cross-chat bridge planned for a future release

If DiscordSRV is present at startup, hChat logs a confirmation so admins know the hook is registered. Forwarding of /msg and /broadcast to Discord is not implemented yet — see ROADMAP.md Phase 5 for the planned bridge.

📊 Metrics (bStats)

hChat bundles bStats for anonymous plugin statistics — no extra download needed. Server owners can disable it with metrics.enabled: false in config.yml or globally in plugins/bStats/config.yml (the toggle applies on the next server start). The plugin id is defined in HChat.java (BSTATS_PLUGIN_ID); register hChat at bstats.org and set it there to start collecting data.


🛠️ Building from Source

Requirements: JDK 21 and Maven 3.5+.

# Clone the repository
git clone https://github.com/hauchdev/hChat.git
cd hChat

# Compile & package
mvn clean package

# The shaded JAR is at: plugin-dist/target/hChat-<version>.jar

ℹ️ Releases — the plugin version lives in one place: the <revision> property at the top of the root pom.xml. Change it there (or pass -Drevision=1.3.0 to Maven) and every module, the filtered plugin.yml version and the final jar name follow automatically. You never have to touch the other 13 POM files.

CI is wired through .github/workflows/build.yml: every push to dev runs mvn clean verify. Tagged v* builds additionally publish a GitHub Release with the packaged JAR.


🤝 Contributing

Pull requests and ideas are very welcome.

Please follow Conventional Commits (Spanish or English both fine), update lang_en.yml / plugin.yml / README.md whenever you add a command, permission, or feature, and make sure mvn clean verify stays green. See ROADMAP.md for the larger picture and upcoming phases.


📄 License

Released under the MIT License.


Made with ❤️ by Hauchdev

Партнёрский материал

Сервер для плагина hChat - как у профи

Плагин hChat создан для серверов: на своём сервере вы настраиваете его под себя и решаете, кому играть. Создать сервер с плагином hChat для друзей можно за пару минут - BungeeHost всё уже подготовил.

Часто задаваемые вопросы

Совместимость

Minecraft: Java Edition

26.2.x26.1.x1.21.x1.20.x1.19.x1.18.x

Платформы

Поддерживаемые окружения

Сервер

Зависимости

Ссылки

Создатели

Детали

Лицензия:
Опубликован:2 месяца назад
Обновлён:1 месяц назад
Главная