LoChat/TODO.md

7.5 KiB
Raw Blame History

LoChat Development TODO

Last updated: 2026-08-04


✅ CRITICAL FIXES (blocking release — from code review 2026-08-04, all DONE)

1. Translation: async + bounded cache, no String.intern(), out of render() ✅

  • renderer/EnhancedChatRenderer.java — removed blocking applyTranslation() from render() (zero network I/O in render path). Translation is now delivered via async action bar (sendTranslationAsync → translateAsync().thenAccept).
  • translate/TranslationService.java — no more String.intern(); bounded LRU cache (2000 entries, synchronized LinkedHashMap); translateAsync runs on a dedicated 2-thread daemon executor; failures return original text, never throw.

2. Atomic file writes (temp + rename, per-file lock) for all persistence ✅

  • utils/persistence/FilePersistence.java — saveYaml/saveJson now write <name>.tmp + Files.move(ATOMIC_MOVE, REPLACE_EXISTING) under a per-file ReentrantLock.
  • core/service/PlayerServiceImpl.java — statsLock serializes async persistPlayerMessages and main-thread saveAll().
  • core/service/PunishmentServiceImpl.java — removed saveAsync() from isBanned() read path.
  • core/service/mute/MuteDataStorage.java — uses FilePersistence.saveJson (atomic), dropped raw FileWriter.
  • core/service/mute/MuteHistoryManager.java — atomic temp+rename write under per-file lock, no e.printStackTrace().

3. Route /g and /l through the same filter pipeline + escape MiniMessage ✅

  • core/service/ChatServiceImpl.java — String messages now run length check → MessageService.processMessage (mute/cooldown) → AdvancedMessageFilter → MiniMessage.escapeTags() → component (colors only with lochat.chat.colors). Component messages bypass (trusted internal). Local radius from AppearanceConfig.
  • commands/chat/GlobalChatCommand.java, LocalChatCommand.java — pass plain String, no more MM.deserialize(raw input).
  • LoChat.java/PluginInitializer.java — filter instance stored on plugin; ServiceRegistry builds MessageService before ChatService.

4. Remove duplicate Discord send; single global/local detection ✅

  • listener/DiscordEventListener.java — deleted the onChat(AsyncChatEvent) handler; ChatEventListener is now the single send path with correct isGlobal.

5. Fix config key mismatches (underscore vs dash / nesting) ✅

  • config/AppearanceConfig.java — chat.local-radius, chat.clear-lines, chat.min-message-length, chat.max-message-length, chat.colors.* (dash), prefixes.*.separator (string), discord.avatar-urls.*, discord.event-titles.* (+ _→- normalization).
  • integrations/discord/DiscordConfig.java — webhook.avatar-url, chat.global-only, chat.use-embed, chat.embed-color, filter.* (dash), performance.retry-*.
  • config/MuteConfig.java — settings.*, notifications.*.
  • config/SoundsConfig.java — messages.mention.*, messages.private-message.*, commands.success.*.
  • config/FiltersConfig.java + filters — config/filters.yml is now the single source of truth (caps.max-caps-percent, swear.replace, hidden-urls.*, spam.max-repeating-chars, flood.max-same-messages).
  • gradient/config/GradientConfig.java — nested keys gradient.limits.*, gradient.pricing.*, gradient.cooldowns.*, gradient.formatting.*, gradient.storage.type → SQLite now detected.
  • managers/AutoMessageManager.java + config.yml — reads automessages.messages (new automessages: section added to config.yml), honors automessages.random.

✅ COMPLETED THIS SESSION

Architecture (SOLID/KISS/DRY)

  • AppearanceConfig — fixed double-call bug
  • config/ — 9→3 files per folder (subfolders: chat/, filter/, mute/, manager/)
  • api/service/ + core/service/ — 8→3 files per folder (subfolders: chat/, player/, moderation/, pm/, spy/, ignore/)
  • ConfigManager — god class → facade + 6 managers (Chat/Pm/Mention/ClearChat/CustomMessages/Filters)
  • MessagingService — fat interface → 3 services (PrivateMessageService/SpyService/IgnoreService)
  • AdvancedMessageFilter — hardcoded pipeline → FilterPipeline with dynamic registration
  • 25 commands → BaseCommand/AdminCommand/PlayerCommand hierarchy
  • MuteCommand — decomposed into helper methods (KISS fix)

Encapsulation

  • ChatEventListener — removed instanceof cast to PlayerServiceImpl
  • PunishmentSnapshot — mutable fields → private + getters
  • BaseConfig — protected fields → private + protected getters
  • 29 files with import.* → explicit imports

Checkstyle

  • Config: 4-space indent, 140-char lines, Google-style naming/quality
  • Warnings: 520 → 0 (both main and test)
  • Wired into build.gradle.kts

Configs

  • All rewritten: clean, English comments, no Spacelegacy palette

🟡 NEXT: NEW FEATURES

1. Channels (like VentureChat / Carbon)

  • /join, /leave, /channel — full channel system: global, local, staff, trade, party.
  • Per-channel colors, aliases, permissions, cooldowns, spy mode.
  • Party chat: private groups /party.
  • Network channels (Bungee/Velocity) sync.

2. Anti-swear hardening + filter statistics

  • Bypass obfuscation: q→р leet/Unicode substitution, repeated chars between letters, spaces/dots inside words.
  • Track filter stats (how many messages blocked per filter) → expose via command/placeholder.

3. Stable plugin API + API events

  • Publish api/ modules to a repo so third-party plugins can depend on it.
  • Add api-version hint / provides in plugin.yml for dependency resolution.
  • Dedicated API events: LoChatMessageEvent, LoChatFilterEvent, LoChatPunishEvent etc.

4. DiscordSRV-style 2-way bridge (Discord → chat)

  • Read messages from a Discord channel (bot or webhook listener) and relay into Minecraft chat.
  • Channel ↔ Discord channel mapping.

5. Full spy + auto-mute for spam

  • PM spy + command spy with custom formats (like VentureChat).
  • Auto-mute repeat offenders (spam/flood) with configurable threshold and duration.

🔵 LOWER PRIORITY (carry-over)

1. Shared Persistence Utility

5 services repeat load/save/ensureDir pattern:

  • NickServiceImpl, PlayerServiceImpl, ChatServiceImpl, PunishmentServiceImpl, IgnoreServiceImpl

Fix: Extract FilePersistenceUtil or base class

2. Persist nicknames on change

NickServiceImpl.java:77 mutates only in-memory map; save() only on shutdown → nicknames lost on crash (async save after mutation).

3. DIP: Service Locator Anti-Pattern

ServiceRegistry.get(Xxx.class) used everywhere instead of constructor DI. Big refactor.

4. DRY: PM Send Logic Duplicated

MsgCommand + ReplyCommand still have near-identical send logic.

5. Fix cooldown map collision

PlayerServiceImpl.java:80-82 — all non-global types (local chat + RP /me /do /try /roll) share one map → cross-blocking cooldowns. Split per-type maps.

6. Thread-safe flood/spam deques

FloodFilter.java:32, SpamFilter.java:30 use plain ArrayDeque written from async threads, read from main → use synchronized/thread-safe structures.

7. Tests

Only 11 test files for 155 main files. Very low coverage (JaCoCo wired, CI uploads report).

8. No PM cooldown

chat.pm.cooldown: 2 in config.yml is never read → /msg spam unthrottled.


📋 KNOWN ISSUES

  • Gradients may not display correctly on clients < 1.16
  • Some filters may block legitimate messages (configurable in config/filters.yml)