First feature release of the zh-TW fork. Backend hardening, complete redesign of the in-game editor, and a proper internationalisation pipeline. - #4
Conversation
…ed editor GUI Phase 1 — backend optimizations: - KothTicker now isolates per-koth tick exceptions - RefreshInsideKothService uses world.getNearbyEntitiesByType instead of iterating all online players per koth per second - OfflineRewardStorage persists rewards for offline winners (YAML + rtag Base64), auto-delivered on next join with drop protection - Reward drops use Item#setOwner so other players cannot steal - Plugin Logger replaces Bukkit.getLogger across the project - KothYamlSaver gains async saveToYamlAsync for editor flows - NotifyChannel enum + NotifyType.channels() lay groundwork for arbitrary channel combinations Phase 2 — disable team mechanism (surface layer): - TeamCommand is no longer registered - KothBuilder forces solo=true and ignores team-related YAML keys - Team toggles removed from the create/edit GUI - Underlying API/events/hooks preserved for future re-enable Phase 3 — CreateKothGui redesign: - 6-row, 3-tab layout (Basic / Time & Scoreboard / Rewards & Commands) - Footer with Test, Copy-from-other-KOTH, validation summary, Save - Inline red/green field validation with translated error messages - ID character validation + captureTime <= maxTime guard - Editing existing KOTH detected automatically; save button distinguishes Create vs Edit (Slime Ball vs Anvil) and unregisters old before re-registration - Slot magic numbers replaced with named constants - chatPromptItem / numericItem / toggleItem factories cut boilerplate - KothLoreBoardPreview now caches per-player and invalidates on edit - One-click 'Test this KOTH' button Deferred for follow-up: - Anvil GUI text input (needs custom InventoryType.ANVIL wrapper) - Per-line scoreboard editor (needs index-based KothTempData API)
- README.md is now the Traditional Chinese landing page covering the fork's localization, backend optimizations, and redesigned editor GUI - Original Smarts Hub README preserved verbatim as README_author.md, linked prominently at the top of the new README
Phase 3.2 — replace 'close window + chat input' with Anvil GUI: - Add AnvilTextInput utility wrapping Bukkit InventoryType.ANVIL - Listens for PrepareAnvilEvent to keep result slot synced with rename text - Listens for click on result slot (confirm) and inventory close (cancel) - Uses AnvilView#getRenameText / setRepairCost (Paper 1.21 API) - CreateKothGui swaps chatPromptItem -> promptItem with a Consumer setter and an optional validator; ID, display name, both scoreboard titles now open Anvil with live validation feedback Phase 3.3 — per-line scoreboard editor: - Add KothTempData index-based line API (getLines, setLineAt, removeLineAt, insertLine, moveLine) - New ScoreboardLineEditorGui: 6-row paginated layout, one line per row with edit / up / down / delete buttons, header for add / clear / back - Edit and add go through AnvilTextInput - CreateKothGui's scoreboard line items now open this editor instead of the 'right click = add, left click = remove last, shift = clear' hack
The new editor code added in the previous release was hardcoded zh-TW,
which broke any non-Chinese localisation. This commit moves every
user-facing string in:
- CreateKothGui (tabbed editor, validation, footer, all items)
- ScoreboardLineEditorGui (header, per-line row, pagination)
- KothLoreBoardPreview (preview hint and content lines)
behind keys in messages.yml. English defaults live in messages.yml;
the fork's Traditional Chinese translations live in messages_zh_tw.yml
under the same key tree.
Changes:
- MessageRepository gains fmt(path, ...args) and fmtList(path, ...args)
that substitute {0}, {1}, ... positional placeholders.
- New 'gui:' tree in messages.yml / messages_zh_tw.yml covering
gui.common, gui.create-koth, gui.scoreboard-editor, gui.board-preview,
gui.reward.
- CreateKothGui constructor now takes MessageRepository and an injected
KothLoreBoardPreview (shared with ScoreboardLineEditorGui so the
preview cache is consistent).
- OfflineRewardStorage keeps an English fallback message: it is
constructed before the GUI services are wired and pulling
MessageRepository through that path would just complicate ordering.
Deferred to a follow-up: the legacy GUIs created earlier
(EditKothListGui, AddPhysicalRewardGui, CommandGui, CreateSchedulerGui)
still contain hardcoded zh-TW strings; they will be migrated to the
same i18n pattern in a separate pass.
Completes the i18n pass by moving the four GUIs added during the earlier Gemini work to the same key-based pattern as the new editor: - EditKothListGui (~7 strings) - AddPhysicalRewardGui (~12 strings) - CommandGui (~14 strings, includes per-type lore + chat prompt) - CreateSchedulerGui (~18 strings, includes 7 weekday names) All four constructors now take MessageRepository alongside MessageParser and SHKoth#guis() passes it through. Adds to messages.yml / messages_zh_tw.yml: gui.edit-list.* gui.add-reward.* gui.command-editor.* (with type-winner/start/end variant keys) gui.scheduler.* (with day-monday..day-sunday variant keys) With this commit there are no hardcoded zh-TW strings left in any of the editor flow. Server messages, broadcast, title, actionbar, sound, and bossbar were already i18n-aware before this pass.
| import java.util.Set; | ||
|
|
||
| /** | ||
| * KOTH 通知可用的個別頻道。未來 NotifyService 可依此 EnumSet 過濾。 |
There was a problem hiding this comment.
Classes & Methods comments should be in English so others contributors can understand.
| guiService.openCreateKothGui(actor.asPlayer()); | ||
| } | ||
|
|
||
| @Subcommand({"editor", "edit", "gui"}) |
There was a problem hiding this comment.
Editor seems to not be working properly, tab items overlap slots and they keep showing in other tabs.
| } else if (offlineStorage != null) { | ||
| offlineStorage.add(winnerId, item); | ||
| } else { | ||
| logger().warning("離線獎勵儲存未初始化,獎勵遺失 (winner=" + winnerId + ")"); |
| new KothCommand(kothRegistry, notifyService, configService, guiService)); | ||
| // 組隊機制已於此版本停用:TeamCommand 不再註冊,相關 GUI toggle 已下架。 | ||
| // 底層 service/listener 仍保留以維持 API 相容;若未來要重新啟用,恢復下行即可。 | ||
| // lamp.register(new TeamCommand(teamHandlingService, teamInviteService, teamInformationService)); |
There was a problem hiding this comment.
Plugin uses an internal team system, to keep it active and dont clash into others team plugins hooks, it could be a config option to disable the command.
There was a problem hiding this comment.
If this is a WIP I undestand going back to your language to keep the development, must be configurable to spect a merge.
There was a problem hiding this comment.
When testing option rename didn't work even when plugin was registering the listeners, also item can be moved and kept in the player inventory, closing doesn't open creation, editor gui back.
Might be WIP?
There was a problem hiding this comment.
Mentioned early on another commit, tab items overlap/don't get replaced properly.
The previous AnvilTextInput built an inventory via Bukkit.createInventory(ANVIL), which has no anvil menu backend: the rename field did not apply, the paper item could be dragged into the player's inventory, and closing did not reliably return to the editor. Switch to net.wesjd:anvilgui (relocated into the plugin's libs package), which opens a genuine anvil menu, cancels item movement, and manages its own listeners. Confirm and cancel both re-open the caller on the next tick. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KKymHBBoAH2xx8X9N5aBD
…ub#4 P0-3) Language policy for upstream: developer-facing text (comments, Javadoc, log/exception messages) is English; player-facing text goes through MessageRepository. Translate all remaining Traditional Chinese in dev-facing strings across the reward, koth, listener, GUI-cache and API guideline classes. NotifyType display labels are reduced to plain English ("Title", "Chat", "Bossbar", "All") since they surface in the editor GUI. After this change a repo-wide scan finds zero CJK characters in Java source; only the zh_tw language resource files retain Chinese, as intended. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KKymHBBoAH2xx8X9N5aBD
…ap (PR Smarts-Hub#4 P0-1, P0-4) P0-4 — keep the internal team system, make disabling it a config option: - Add hooks.yml `internal-team.disable-command` (default false). When true, the built-in team command is not registered and the team-mode editor toggles are hidden. All team services, listeners, hooks and API stay active so other team plugins can still integrate. - KothBuilder: stop hardcoding `isSolo = true`. Read `solo-koth`, `deny-entry-if-not-in-team` and `create-team-if-not-exists` from the KOTH config — the keys the template and the editor's YamlSaver actually write (this also fixes the pre-existing mismatch where the builder read `solo-mode`, a key nothing writes). - Restore the solo/team, deny-entry and auto-create-team toggles in the editor's Basic tab (row 4), gated on the same config option. New strings are routed through MessageRepository with English defaults + zh_tw overrides. P0-1 — editor tab overlap: refreshAll() now calls gui.clearItems() to clear triumph-gui's logical item map, not just the backing inventory, so items from a previous tab no longer bleed into the next one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KKymHBBoAH2xx8X9N5aBD
Mark all five PR Smarts-Hub#4 P0 items landed and build-verified; note the KothBuilder config-key fix and the remaining in-game verification + P1 follow-ups. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017KKymHBBoAH2xx8X9N5aBD
… can capture Previously the whole teamless-player branch was gated on denyEnterWithoutTeam, so with deny disabled a teamless player could walk into a team KOTH but the tally could never resolve them to a team and capture never started. Now a team-mode KOTH always tries to auto-assign a team first (when create-team-if-not-exists allows it) and only then applies the deny rule. Verified in-game on Paper 1.21.1: teamless player enters a team KOTH with create-team-if-not-exists=true, gets an internal team, capture starts and resolves a winner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Thanks for the detailed review, @yiyoperez — this was really helpful. I've gone through all seven points; here's how each is addressed. The changes are split into focused commits so they're easy to audit. Summary of commits
1.
|
First feature release of the zh-TW fork. Backend hardening, complete redesign of the in-game editor, and a proper internationalisation pipeline.