docs: chat plugin research (ChatChat + VentureChat)
Carbon viewer-context bug: <luckperms_prefix> resolves against viewer not sender. Researched two open-source alternatives. Both fix the bug. ChatChat (HelpChat fork) renders per-recipient with PlaceholderAPI.setPlaceholders(sender, ...) + Kyorifier converts legacy & codes to MM. VentureChat resolves PAPI once vs sender, splits packets via ProtocolLib. Concerns: - ChatChat: 0 GitHub releases, last commit 2025-04-02, apiVersion 1.21.4, uses deprecated AsyncPlayerChatEvent - VentureChat: built for 1.21.8, open issues #154/#156/#157 report 1.21.10+ breakage with no maintainer response 4+ months Both verdicts: cautious recommend. Operator decision pending player input + migration plan synthesis.
This commit is contained in:
parent
4c16cebb2b
commit
d25b3d2e0d
2 changed files with 205 additions and 0 deletions
99
docs/CHAT-PLUGIN-CHATCHAT-RESEARCH.md
Normal file
99
docs/CHAT-PLUGIN-CHATCHAT-RESEARCH.md
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
# ChatChat Migration Research — racked.ru
|
||||||
|
|
||||||
|
**Date:** 2026-05-07
|
||||||
|
**Target:** Replace CarbonChat 3.0.0-beta.36 (viewer-context bug on `<luckperms_prefix>`)
|
||||||
|
**Source:** `HelpChat/ChatChat` — repo URL `github.com/HelpChat/ChatChat` (the `HibiscusMC/ChatChat` URL 404s; HelpChat is the actual maintainer org — DeluxeChat / extendedclip family).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Project Health — RISKY
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
|---|---|
|
||||||
|
| Last commit (main) | 2025-04-02 (PR #230 merge) — ~13 months ago |
|
||||||
|
| Substantive 1.21.4 work | 2025-02-26 (one-shot bump) |
|
||||||
|
| Releases on GitHub | **0** (CI artifacts only) |
|
||||||
|
| Jenkins last build | #79, ~13 months ago, marked stable; CI appears idle |
|
||||||
|
| Open issues / PRs | 23 open non-PR issues (some open since 2022) |
|
||||||
|
| License | MIT |
|
||||||
|
| Stars / forks | 51 / 31 |
|
||||||
|
| README | Literally says "Coming Soon :tm:" |
|
||||||
|
| API target | `apiVersion: 1.21.4` in plugin.yml; Spigot 1.21.4-R0.1-SNAPSHOT |
|
||||||
|
| Adventure / MiniMessage | 4.16.0 (somewhat behind 4.20.x current) |
|
||||||
|
|
||||||
|
Verdict: low velocity, no formal release, niche maintainers (M0diis, BlitzOffline, bridgelol). Functional but not a "thriving" project — expect to fork or pin a build.
|
||||||
|
|
||||||
|
## 2. Architecture — Would It Fix Our Bug? **YES (with caveats)**
|
||||||
|
|
||||||
|
`MessageProcessor.process()` iterates every recipient and re-renders the format **per-recipient** via `FormatUtils.parseFormat(format, sender, recipient, message, miniPlaceholders)`. Inside that call:
|
||||||
|
|
||||||
|
- `PlaceholderAPI.setPlaceholders(player=sender, formatString)` — `%luckperms_prefix%` always resolves against the **sender**. This is the exact opposite of Carbon's bug.
|
||||||
|
- `PlaceholderAPI.setRelationalPlaceholders(sender, recipient, ...)` — `%rel_*%` get both contexts.
|
||||||
|
- A `<papi:luckperms_prefix>` MM tag also exists, also bound to sender via `createPlaceholderAPITag(player=sender)`.
|
||||||
|
- `Kyorifier.kyorify()` then converts any `&` legacy codes returned by PAPI (e.g. `&8[&4⛧&8]`) into MiniMessage tags **before** parsing. The legacy-code workaround Carbon swallows works natively here.
|
||||||
|
- A separate internal `MiniPlaceholderManager` resolves config-defined MM tags with explicit `MiniPlaceholderContext.builder().sender(user).recipient(target)` — sender-context guaranteed.
|
||||||
|
|
||||||
|
Caveat: ChatChat's bundled `MiniPlaceholderManager` is its own config-yaml system. The external **kyori MiniPlaceholders** library + LP-Expansion (which provides the bare `<luckperms_prefix>` MM tag) is **not auto-bridged**. Two practical fixes:
|
||||||
|
1. Use `%luckperms_prefix%` PAPI placeholder in the format (Kyorifier converts `&` codes) — works out of the box.
|
||||||
|
2. Or use `<papi:luckperms_prefix>` MM tag — same effect.
|
||||||
|
|
||||||
|
Either way the viewer-context bug disappears.
|
||||||
|
|
||||||
|
## 3. Feature Gap vs Carbon (only what matters here)
|
||||||
|
|
||||||
|
| Feature | Carbon 3.0 | ChatChat | Notes |
|
||||||
|
|---|---|---|---|
|
||||||
|
| Channels (multi, per-channel format) | yes | yes | `channels.yml` + per-channel formats list |
|
||||||
|
| `/<channel>` toggle / message-prefix | yes | yes | `toggle-command`, `message-prefix` |
|
||||||
|
| Mute / ignore | yes | yes | `/ignore`, `/ignorelist`, GP soft-mute hook |
|
||||||
|
| Mentions (with sound) | yes | yes | personal + everyone, perm-gated, sound configurable |
|
||||||
|
| Profanity / rules | yes | basic (RuleManager + unicode rule) | likely needs simple regex rules |
|
||||||
|
| DiscordSRV bridge | yes | yes (channels-bridging on, name-matched) | uses DSRV `ChatHook` interface |
|
||||||
|
| PlaceholderAPI + Vault | yes | yes (PAPI hard-dep) | Vault implicit via `%vault_group%` examples |
|
||||||
|
| MiniPlaceholders (external lib) | yes (native) | **no auto-bridge** — use PAPI tag instead | minor format rewrite |
|
||||||
|
| `<itemlink>` / `<item>` in chat | `<itemlink>` | `<item>` (perm `chatchat.tag.item`) | tag name differs |
|
||||||
|
| Hover/click on names/items | yes | yes | full MM standard tags, perm-gated |
|
||||||
|
| Chat preview (1.19+) | partial | no (uses deprecated `AsyncPlayerChatEvent`) | preview gone in 1.19.3+ anyway |
|
||||||
|
| Cross-server / Velocity | yes | no (single-server only) | matches our setup |
|
||||||
|
| Async chat | yes | rides Bukkit async event | open issue #91 wants deeper async |
|
||||||
|
| Database backend | H2/MySQL/JSON | **JSON only** (`GsonDatabase`) | fine for our scale |
|
||||||
|
|
||||||
|
## 4. Migration Cost — **MEDIUM**
|
||||||
|
|
||||||
|
What breaks / needs work:
|
||||||
|
- **Permission rename:** `carbon.channel.global.see` → `chatchat.channel.see.global`; same for `use`. Plus `chatchat.tag.*` per-tag perms (color/hover/click etc) need granting in LP (Carbon doesn't split these).
|
||||||
|
- **Format syntax rewrite:** Carbon uses a single MM string per format. ChatChat splits formats into named `parts:` (channel/prefix/name/divider/message). Operator's target string maps cleanly onto one `default` format with one part.
|
||||||
|
- **DiscordSRV config:** ChatChat-channel name MUST match DSRV-config channel name (not Discord channel name). Re-check `DiscordSRV/config.yml > Channels:` keys.
|
||||||
|
- **User data:** Carbon JSON/H2/MySQL nicknames don't carry over; ChatChat starts a fresh `users.json`. EssentialsX nicknames are unaffected (different store).
|
||||||
|
- **Item-tag rename:** any `<itemlink>` in messages must become `<item>`.
|
||||||
|
- **External MiniPlaceholders ignored** — operator's `<luckperms_prefix>` MM tag becomes `%luckperms_prefix%` (PAPI form) inside the format.
|
||||||
|
- **partychat removal:** trivial — just don't define it in `channels.yml`.
|
||||||
|
|
||||||
|
What's preserved automatically: LP prefixes-as-`&`-codes (Kyorifier handles them), EssentialsX nickname display via `%player_displayname%`, Discord routing intent, gray-message rendering (`<gray><message>`), MiniMOTD/TAB/ProAntiTab/ProtocolLib (no overlap).
|
||||||
|
|
||||||
|
## 5. Verdict — **CAUTIOUS RECOMMEND**
|
||||||
|
|
||||||
|
ChatChat will fix the viewer-context bug because its renderer is per-recipient with explicit sender-context PAPI resolution and a built-in legacy-code Kyorifier — but it's a sleepy single-Jenkins-build project pinned to 1.21.4 with no formal releases, so adopt only if you're comfortable building from source and pinning a known-good commit.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Top 3 unknowns to verify before pulling the trigger
|
||||||
|
|
||||||
|
1. **1.21.11 runtime compatibility.** plugin.yml says `apiVersion: 1.21.4`. Need to test the latest CI jar (or build commit `5b9...` on a Purpur 1.21.11 staging instance) and confirm no NMS/AsyncPlayerChatEvent regressions on Purpur. Paper still fires the deprecated event so likely OK, but verify on an actual 1.21.11 Purpur jar before swapping in prod.
|
||||||
|
2. **DiscordSRV 1.25.1 vs whatever you currently run.** ChatChat compiles against DSRV 1.25.1; the `ChatHook` interface or the shaded Adventure-Gson serializer dance can break across DSRV versions. Test in/out routing on a staging server.
|
||||||
|
3. **MiniPlaceholders LP-Expansion: do you actually need the MM tag form?** If any other plugin (MOTD, TAB) consumes `<luckperms_prefix>` as a MiniMessage tag from racked formats, it must keep working. Confirm switching to `%luckperms_prefix%` (PAPI) doesn't break TAB/MiniMOTD elsewhere — those may be unaffected since they have their own resolvers.
|
||||||
|
|
||||||
|
## Source artefacts inspected (for re-audit)
|
||||||
|
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/util/MessageProcessor.java` — per-recipient render loop
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/util/FormatUtils.java` — sender-context PAPI call
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/util/PapiTagUtils.java` — `<papi:...>` MM tag bridge
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/util/Kyorifier.java` — legacy `&`/hex → MM converter
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/listener/ChatListener.java` — uses `AsyncPlayerChatEvent`
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/util/ChannelUtils.java` — `chatchat.channel.{see,use}.<name>` perms
|
||||||
|
- `plugin/src/main/java/at/helpch/chatchat/hooks/dsrv/{ChatChatDsrvHook,DsrvListener}.java`
|
||||||
|
- `plugin/src/main/resources/{channels,formats,extensions,settings}.yml`
|
||||||
|
- `plugin/build.gradle.kts` — apiVersion 1.21.4, soft-deps Towny/DSRV/SuperVanish/GP, loadBefore Essentials
|
||||||
|
- `gradle/libs.versions.toml` — Spigot 1.21.4, MM 4.16.0, DSRV 1.25.1, EssX 2.19.4, PAPI 2.11.6
|
||||||
|
|
||||||
|
Last upstream commit reviewed: `Merge pull request #230 from M0diis/resolve-228` @ 2025-04-02T17:18:51Z.
|
||||||
106
docs/CHAT-PLUGIN-VENTURECHAT-RESEARCH.md
Normal file
106
docs/CHAT-PLUGIN-VENTURECHAT-RESEARCH.md
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
# VentureChat Research — Replacement for Carbon 3.0.0-beta.36
|
||||||
|
|
||||||
|
**Date:** 2026-05-07
|
||||||
|
**Target:** racked.ru (Purpur 1.21.11, single server, no Velocity)
|
||||||
|
**Repo:** github.com/Aust1n46/VentureChat
|
||||||
|
**Verdict (one line):** **Cautious recommend** — architecture fixes the viewer-context bug, but maintainer is slow and 1.21.10/.11 has open bug reports unresolved since Jan 2026.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Project Health
|
||||||
|
|
||||||
|
| Signal | Value |
|
||||||
|
|---|---|
|
||||||
|
| Latest release | **v3.8.0** (2025-08-20) — built for 1.21.8 |
|
||||||
|
| Last commit on master | 2025-08-20 (`b9e19e2` — 1.21.8 update) |
|
||||||
|
| Previous commit gap | 6 months (2025-02 → 2025-08) |
|
||||||
|
| Open issues | 71 (incl. #157 "update for 1.21.10!!!", #154 sound fix, #155 `/msg` crashes server, #146 `/tell` crashes 1.21.4) |
|
||||||
|
| Stars | 48 |
|
||||||
|
| License | **GPL-3.0** |
|
||||||
|
| API version declared | `1.13` (means it should load on 1.21.x but no native Paper API use) |
|
||||||
|
|
||||||
|
**Status: maintained but slow.** One active maintainer (Aust1n46). Long gaps between updates. Multiple users requesting 1.21.10+ updates with no response yet. **Risky for a 1.21.11 server today** — v3.8.0 was tested against 1.21.8.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Architecture — Does it fix the viewer-context bug?
|
||||||
|
|
||||||
|
**Yes, by design.** Evidence from `src/main/java/mineverse/Aust1n46/chat/utilities/Format.java` and `listeners/ChatListener.java`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// Format is built ONCE, against the SENDER (icp = MineverseChatPlayer sender):
|
||||||
|
PlaceholderAPI.setBracketPlaceholders(icp.getPlayer(), placeholder)
|
||||||
|
format = Format.FormatStringAll(PlaceholderAPI.setBracketPlaceholders(mcp.getPlayer(), ...));
|
||||||
|
|
||||||
|
// Then dispatched per-recipient as a pre-rendered packet — placeholders NOT re-resolved per viewer:
|
||||||
|
for (Player p : recipients) {
|
||||||
|
String json = Format.formatModerationGUI(globalJSON, p, mcp.getName(), channel.getName(), hash);
|
||||||
|
PacketContainer packet = Format.createPacketPlayOutChat(json);
|
||||||
|
Format.sendPacketPlayOutChat(p, packet);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This is the **pre-1.19 chat model** — VentureChat hooks the legacy `AsyncPlayerChatEvent` and ships rendered JSON packets via ProtocolLib. It does **not** implement Paper's `AsyncChatEvent` `ChatRenderer` (which is what causes Carbon to re-render the format per viewer and resolve `<luckperms_prefix>` against each viewer instead of the sender).
|
||||||
|
|
||||||
|
**Plugin → player `sendMessage` interception:** Not intercepted. VentureChat only acts on the chat event; `Player.sendMessage()` and `Audience.sendMessage()` bypass it entirely. Good for plugins that send system messages directly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Feature Parity vs Carbon (only diffs that matter)
|
||||||
|
|
||||||
|
| Feature | Carbon | VentureChat |
|
||||||
|
|---|---|---|
|
||||||
|
| Format syntax | MiniMessage | **Legacy `&` codes only** (no MM, no Adventure Component) |
|
||||||
|
| Channels | yes | yes (alias, distance, perm, color, format, filter, mutable, autojoin, cooldown) |
|
||||||
|
| Channel cmd / focus | `/ch <name>` | per-channel alias (e.g. `/g`) + `/channel` |
|
||||||
|
| Mute / ignore | yes | yes (per-channel mute, time-based mutes `10m`/`1h`/`1d`) |
|
||||||
|
| Mentions / pings | yes | yes (configurable sound + format) |
|
||||||
|
| Profanity filter swap | yes | yes (regex `pattern,replacement`) |
|
||||||
|
| DiscordSRV | yes | **yes** — first-class hook, channel-link config |
|
||||||
|
| PAPI | yes | yes (`{vault_prefix}`, `{player_displayname}`, `{venturechat_channel_prefix}`, `sender_*`/`receiver_*`) |
|
||||||
|
| **MiniPlaceholders** | yes | **NO native support** — only PAPI bracket placeholders |
|
||||||
|
| Vault group prefix | via PAPI | via Vault directly + `{vault_prefix}` |
|
||||||
|
| Hover/click events | MM tags | Per-group `hover_text` / `click_action` / `click_text` lists in config |
|
||||||
|
| 1.19+ signed chat | preview-aware | Cancels & reships as packets — preview not used |
|
||||||
|
| Bungee/Velocity | yes | yes (irrelevant for racked.ru) |
|
||||||
|
|
||||||
|
**Material gaps:** No MiniMessage, no MiniPlaceholders. LP Expansion via PAPI bracket placeholders works (it's just `{luckperms_prefix}` etc.).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Migration Cost: **Medium**
|
||||||
|
|
||||||
|
Concrete breakage list:
|
||||||
|
- **Format rewrite:** every Carbon MM format string `<luckperms_prefix><sender_displayname> <gray>»</gray> <message>` becomes legacy `&` form: `{luckperms_prefix}{player_displayname} &7» &f{message}`. Hover/click move from MM tags to per-group YAML.
|
||||||
|
- **MiniPlaceholders dropped.** If anything in current chat-format uses MM-only tags or MiniPlaceholders-exclusive resolvers, those need PAPI equivalents.
|
||||||
|
- **Permission rename:** `carbon.*` → `venturechat.<channel>` (e.g. `venturechat.global`), plus `venturechat.mute`, `venturechat.staffchannel`, etc. LuckPerms group nodes need a one-pass rewrite.
|
||||||
|
- **User data:** mute/ignore lists not migratable from Carbon — players re-mute fresh.
|
||||||
|
- **DiscordSRV config:** channels block needs the VentureChat channel name, not Carbon's. Format templates in DiscordSRV `messages` may need adjustment if they referenced Carbon-specific placeholders.
|
||||||
|
- **partychat:** delete the channel block in `config.yml`; remove the LP perm grant.
|
||||||
|
|
||||||
|
LP `&`-coded prefixes are **already legacy**, so they render natively — no Carbon-style `<reset>` wrapping needed. This is the biggest migration win.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Specific Bug Check
|
||||||
|
|
||||||
|
| Bug | Carbon | VentureChat |
|
||||||
|
|---|---|---|
|
||||||
|
| `<luckperms_prefix>` resolves to viewer's prefix | YES (per-viewer ChatRenderer) | **NO — resolves once against sender** (verified in source) |
|
||||||
|
| Plugin → player `sendMessage` silently dropped | Possibly intercepted by ChatRenderer | **Not intercepted** — no AsyncChatEvent hook, no Audience interception |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Performance / Maturity
|
||||||
|
|
||||||
|
- Long-running plugin (originally MineverseChat, ~10 years old, #1 chat plugin on Spigot historically).
|
||||||
|
- Memory footprint expected low — no Adventure Component graph, just string ops + JSON.
|
||||||
|
- ProtocolLib dependency adds a small overhead per chat packet but is already on the server.
|
||||||
|
- No specific 1000+ player evidence found; reviews indicate widespread use on mid-size networks.
|
||||||
|
- **Risk:** open `/msg` and `/tell` crash issues on 1.21.4/1.21.5 (#146, #155) — must verify these are fixed in v3.8.0 or test before going live.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verdict
|
||||||
|
|
||||||
|
**Cautious recommend.** Architecture is the right shape to fix the viewer-context bug — placeholders resolved once against sender, no Paper ChatRenderer pipeline, plugin sendMessage untouched. **But** v3.8.0 targets 1.21.8 (not .11), maintainer turnaround is months not days, and there are unresolved crash reports on close-by versions. Stage in a test instance against 1.21.11 first.
|
||||||
Loading…
Reference in a new issue