Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Each package immediately under `feature` owns one user-facing capability. Its se

`platform` adapts external mechanisms such as Forge commands and Mixin. Adapters route external requests to their owners through narrow interfaces. An adapter can implement `ClientLifecycle` to manage its own subscriptions and registrations.

Commands definitions and actions are owned by features. `runtime.command` owns routing, help, completion, and availability of commands. `platform.command` owns Forge registration.
Command definitions and actions are owned by features. `runtime.command` owns routing, help, completion, and availability of commands. `platform.command` owns Forge registration.

`feature.webui` owns the local HTTP server and connects the configuration interface to config and feature APIs. `web-ui` owns the browser pages.

Expand Down
4 changes: 1 addition & 3 deletions docs/DEBUGGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,6 @@ If Gradle sync fails or reports a toolchain error, check that Gradle uses JDK 21

In case the Vite page is opened, but the requests fail, make sure that the game is launched and the `WEB_UI_TARGET` matches the current address of the game. If the configuration interface fails to launch, look for the "Configuration interface is unavailable" message in the game log.

While reporting a failure, provide the relevant log messages and steps to reproduce it.

The saved data is in `12pit/` directory in the Minecraft game directory. Profiles are stored in `12pit/config/`, relations are stored in `12pit/relations.json`, and swap bindings are stored in `12pit/swap-bindings.json`.

Create a backup copy of these files before changing them in order to diagnose a load error. Do not delete the saved data in order to reset a temporary session issue.
Create a backup copy of these files before changing them in order to diagnose a load error.
12 changes: 8 additions & 4 deletions docs/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ The following helpers create settings and register their metadata in the feature

- `booleanSetting` creates a boolean. Use `booleanSetting(id, defaultValue)` for a saved flag that has no interface control.
- `integerSliderSetting` and `doubleSliderSetting` create a numeric setting with default value, minimum, maximum and step parameters.
- `keybindSetting` creates a `KeybindSetting` for one key and an optional Shift, Ctrl, Alt, or Meta key. The main key may also be a modifier. The saved integer keeps the main key in the low byte and the modifier in the next byte. Existing single-key values stay valid. Features use `Keybind.matches` for key events and `Keybind.held` for held input.
- `keybindSetting` creates a `KeybindSetting` for one key and an optional Shift, Ctrl, Alt, or Meta key. The main key may also be a modifier. The saved integer keeps the main key in the low byte and the modifier in the next byte. Features use `Keybind.matches` for key events and `Keybind.held` for held input.
- `colorSetting` stores RGB color as `0xRRGGBB`. `colorPickerSetting` stores ARGB color as `0xAARRGGBB`.
- `choiceSetting` creates a choice with default id and `ChoiceSetting.Choice` instances with stable ids.
- `hudConfig` adds grouped anchor, text shadow, and translation options. It also stores placement and scale for the HUD editor. See [HUD](#hud) for grouping and storage details.
Expand Down Expand Up @@ -128,7 +128,7 @@ private final ConfigChangeListener configListener = changes -> {

`ConfigChangeSet.affects(featureId, settingId)` checks which settings changed. Listeners run after all changes are applied. `snapshot()` copies all registered values. `apply(snapshot)` validates all known values before changing live settings, then sends one notification for the whole set. It applies a complete snapshot: missing known values reset to their defaults, and unknown IDs are ignored. An empty snapshot resets all settings to their defaults. No notification is sent if the resulting values are unchanged.

`recoverSavedValues(snapshot, problems)` restores default values for saved values that are not valid and returns them through the callback. It creates a normalized snapshot but does not apply it. Live input uses a normal validation instead. Profile feature handles saving and switching config snapshots.
`recoverSavedValues(snapshot, problems)` restores default values for saved values that are not valid and returns them through the callback. It creates a normalized snapshot but does not apply it. Profile feature handles saving and switching config snapshots.

## Command

Expand All @@ -148,14 +148,14 @@ commands.register(command);

Use `register(command)` to make `/12pit message` available. If `/message` is supposed to be available too, use `register(command, true)` instead; both will use the same tree. Do not register a command twice. Names and aliases use only lowercase letters, digits, `-` and `_`; `12pit` is reserved as a root name. Names and aliases of siblings mustn't coincide.

Use `register(command, config, standalone)` for commands that belong to a toggleable feature. Call `commands.setActive(config, true)` after the feature starts and `commands.setActive(config, false)` when it stops. These commands are available only while their owner is started and enabled. Otherwise standalone names and aliases are removed and the whole subtree is hidden from `/12pit` help and completion.

`arguments(usage, minimum, maximum)` describes the argument display usage and number range. Default is no arguments. `executes` gets an `ICommandSender` and an array of `String` arguments without the matched command path. Registry checks the argument number; feature can check the values, readiness and result of the action.

A node with children is a group. Without arguments it displays auto-generated help, even if there's a handler. Leaf with a handler executes it, if the argument number is correct. Child's name or alias matches case-insensitively and overrides group's handler. Group handler can accept extra unmatched arguments. Adding a single `help` argument will show group help unless there's an explicit `help` child.

`requires(Predicate<ICommandSender>)` restricts use of a node. Help and completion hide children that cannot be used by the sender. The suggestion callback gets the arguments after the command path, including the current word. Return the complete set of suggestions. The registry filters it by the current prefix case-insensitively and removes duplicates. Return an empty list for no suggestions.

Bootstrap provides [ForgeCommandAdapter](../src/main/java/pit12/platform/command/ForgeCommandAdapter.java) through the `Registrar` of the registry. Features don't register Forge command classes manually. There's no way to unregister commands in Forge. `stop()` disallows execution and completion and `start()` will reuse existing entry points. Registration is closed after the first start.

## Chat feedback

Use [ChatFeedback](../src/main/java/pit12/shared/chat/ChatFeedback.java) for local chat messages: `ChatFeedback.reply(sender, Tone.INFO, message)`. Import `ChatFeedback.Tone` and choose `INFO`, `SUCCESS`, `WARNING`, or `ERROR` based on the outcome. The helper adds the shared prefix and tone color.
Expand Down Expand Up @@ -296,6 +296,10 @@ Subscribe to name changes with `addListener(Runnable)` in `start()`, then read t

Use `bindDisplayNameObserver(UUID, Consumer<String>)` to watch one current Tab entry. Each entry has one observer, called on the client thread after its display name changes. Name queries can also refresh an entry and call its observer. The name keeps formatting codes and may be `null`. Pass `null` as the observer to detach it. The subscription ends when the entry leaves Tab or the connection changes.

[NickTracker](../src/main/java/pit12/runtime/nick/NickTracker.java) provides `isNicked(UUID)` for players in Tab. NPCs are not Nicks.

Keep a [NickListener](../src/main/java/pit12/runtime/nick/NickListener.java) in a field. Register it with `nickTracker.addListener(listener)` in `start()`, then read the current Tab state, because existing entries are not replayed. `onNickChanged(playerId, name, nicked)` runs on the client thread when the status changes. `name` is the profile name. A Nick leaving Tab reports `nicked=false`. Unregister the same listener with `nickTracker.removeListener(listener)` in `stop()`.

[SidebarCache](../src/main/java/pit12/runtime/scoreboard/SidebarCache.java) provides `lines()` for the server sidebar. It returns an immutable snapshot of up to 15 lines in display order. Lines include footer text and keep formatting codes. The objective title is excluded. Each [SidebarLine](../src/main/java/pit12/runtime/scoreboard/SidebarLine.java) provides the entry ID, text, and sorting score through `entry()`, `text()`, and `score()`.

`formattedText(minecraft.fontRendererObj)` removes formatting codes and characters with a width of zero in the Minecraft font. Call it on the client thread. It computes the text on the first call and caches it for that line. Score changes retain the cache. Text changes create a new line with an empty cache.
Expand Down
2 changes: 1 addition & 1 deletion docs/zh-CN/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Source: docs/ARCHITECTURE.md; Based on: 1ba2c692c4ee6c2312b39063b1ebfff6b3732539 -->
<!-- Source: docs/ARCHITECTURE.md; Based on: 0df550b95e0d116f62938a52fcb3b056796879f5 -->

# 12pit 架构

Expand Down
6 changes: 2 additions & 4 deletions docs/zh-CN/DEBUGGING.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Source: docs/DEBUGGING.md; Based on: 1ba2c692c4ee6c2312b39063b1ebfff6b3732539 -->
<!-- Source: docs/DEBUGGING.md; Based on: 0df550b95e0d116f62938a52fcb3b056796879f5 -->

# 运行和调试 12pit

Expand Down Expand Up @@ -66,8 +66,6 @@ npm run format:check --prefix web-ui

如果 Vite 页面已打开,但请求失败,确保游戏已启动,且 `WEB_UI_TARGET` 与游戏当前地址一致。如果配置界面无法启动,在游戏日志中查找 "Configuration interface is unavailable" 消息。

报告故障时,提供相关日志消息和复现步骤。

保存的数据位于 Minecraft 游戏目录中的 `12pit/` 目录。配置方案存储在 `12pit/config/`,关系存储在 `12pit/relations.json`,切换绑定存储在 `12pit/swap-bindings.json`。

为诊断加载错误而修改这些文件前,先创建备份。不要为了重置临时会话问题而删除已保存的数据。
为诊断加载错误而修改这些文件前,先创建备份。
14 changes: 9 additions & 5 deletions docs/zh-CN/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- Source: docs/IMPLEMENTATION.md; Based on: f12f00d52de6f34fb6cd0d9679d6ccce66bf0fbf -->
<!-- Source: docs/IMPLEMENTATION.md; Based on: 0df550b95e0d116f62938a52fcb3b056796879f5 -->

# 12pit 实现

Expand Down Expand Up @@ -96,7 +96,7 @@ public final class StatusConfig extends FeatureConfig {

- `booleanSetting` 创建布尔值。使用 `booleanSetting(id, defaultValue)` 创建需要保存但没有界面控件的布尔标志。
- `integerSliderSetting` 和 `doubleSliderSetting` 创建数值设置,参数包括默认值、最小值、最大值和步长。
- `keybindSetting` 创建一个 `KeybindSetting`,支持一个主键和一个可选的 Shift、Ctrl、Alt 或 Meta 修饰键。主键也可以是修饰键。保存的整数用低字节存主键,下一字节存修饰键。现有单键值仍然有效。功能用 `Keybind.matches` 匹配按键事件,用 `Keybind.held` 判断按住状态。
- `keybindSetting` 创建一个 `KeybindSetting`,支持一个主键和一个可选的 Shift、Ctrl、Alt 或 Meta 修饰键。主键也可以是修饰键。保存的整数用低字节存主键,下一字节存修饰键。功能用 `Keybind.matches` 匹配按键事件,用 `Keybind.held` 判断按住状态。
- `colorSetting` 将 RGB 颜色存储为 `0xRRGGBB`。`colorPickerSetting` 将 ARGB 颜色存储为 `0xAARRGGBB`。
- `choiceSetting` 使用默认 ID 和具有稳定 ID 的 `ChoiceSetting.Choice` 实例创建选项设置。
- `hudConfig` 为 HUD 添加分组后的锚点、文字阴影和翻译选项,并存储 HUD 编辑器使用的位置和缩放。分组和存储细节见 [HUD](#hud)。
Expand Down Expand Up @@ -130,7 +130,7 @@ private final ConfigChangeListener configListener = changes -> {

`ConfigChangeSet.affects(featureId, settingId)` 判断哪些设置发生了变化。监听器在所有变更应用后被调用。`snapshot()` 复制所有已注册的值。`apply(snapshot)` 在修改实时设置前校验所有已知值,然后为整组变更发送一次通知。它应用完整快照,缺失的已知值会重置为默认值,未知 ID 会被忽略。空快照会将所有设置重置为默认值。只有最终值没有实际变化时,才不发送通知。

`recoverSavedValues(snapshot, problems)` 将无效的已保存值恢复为默认值,并通过回调返回这些值。它创建规范化的快照,但不应用它。实时输入改用普通校验。配置方案功能负责保存和切换配置快照。
`recoverSavedValues(snapshot, problems)` 将无效的已保存值恢复为默认值,并通过回调返回这些值。它创建规范化的快照,但不应用它。配置方案功能负责保存和切换配置快照。

## 命令

Expand All @@ -150,14 +150,14 @@ commands.register(command);

使用 `register(command)` 使 `/12pit message` 可用。如果 `/message` 也应可用,改用 `register(command, true)`;两者会使用同一棵树。不要重复注册命令。名称和别名只能使用小写字母、数字、`-` 和 `_`;`12pit` 是保留的根名称。同级节点的名称和别名不得相同。

属于可开关功能的命令使用 `register(command, config, standalone)`。功能启动完成后调用 `commands.setActive(config, true)`,停止时调用 `commands.setActive(config, false)`。只有所属功能已启动且开启时,这些命令才可用。否则会移除独立命令的名称和别名,并从 `/12pit` 的帮助和补全中隐藏整个子树。

`arguments(usage, minimum, maximum)` 描述显示给用户的参数用法和数量范围。默认没有参数。`executes` 接收一个 `ICommandSender` 和一个不包含已匹配命令路径的 `String` 参数数组。注册表检查参数数量;功能可以检查值、就绪状态和操作结果。

有子节点的节点是分组。没有参数时,它显示自动生成的帮助,即使存在处理器。带有处理器的叶节点在参数数量正确时执行处理器。子节点的名称或别名匹配不区分大小写,并覆盖分组的处理器。分组处理器可以接收额外的未匹配参数。添加单个 `help` 参数会显示分组帮助,除非存在显式的 `help` 子节点。

`requires(Predicate<ICommandSender>)` 限制节点的使用。帮助和补全会隐藏发送者无法使用的子节点。补全回调接收命令路径之后的参数,包括当前单词。返回完整的补全建议集合。注册表按当前前缀过滤,不区分大小写,并去除重复项。没有建议时返回空列表。

Bootstrap 通过注册表的 `Registrar` 提供 [ForgeCommandAdapter](../../src/main/java/pit12/platform/command/ForgeCommandAdapter.java)。功能不手动注册 Forge 命令类。Forge 无法注销命令。`stop()` 禁止执行和补全,`start()` 会复用现有入口。首次启动后关闭注册。

## 聊天回显

本地聊天回显统一使用 [ChatFeedback](../../src/main/java/pit12/shared/chat/ChatFeedback.java):`ChatFeedback.reply(sender, Tone.INFO, message)`。导入 `ChatFeedback.Tone`,按结果选择 `INFO`、`SUCCESS`、`WARNING` 或 `ERROR`。共享方法统一添加前缀和消息类型对应的颜色。
Expand Down Expand Up @@ -298,6 +298,10 @@ Bootstrap 为功能提供查询契约。其实时查询和订阅需要客户端

通过 `bindDisplayNameObserver(UUID, Consumer<String>)` 监听一个当前 Tab 条目。每个条目只能绑定一个监听器,显示名变化后在客户端线程上调用。名称查询也可能刷新条目并调用监听器。名称保留格式化代码,也可能为 `null`。将监听器设为 `null` 可取消绑定。条目离开 Tab 或连接变化时,订阅结束。

[NickTracker](../../src/main/java/pit12/runtime/nick/NickTracker.java) 通过 `isNicked(UUID)` 查询 Tab 中的玩家是否为 Nick。NPC 不是 Nick。

将 [NickListener](../../src/main/java/pit12/runtime/nick/NickListener.java) 保存为字段。在 `start()` 中调用 `nickTracker.addListener(listener)` 注册,再读取当前 Tab 状态,因为不会补发已有条目。状态变化时,`onNickChanged(playerId, name, nicked)` 在客户端线程执行。`name` 是档案名称。Nick 离开 Tab 时,`nicked` 为 `false`。在 `stop()` 中调用 `nickTracker.removeListener(listener)` 注销同一个监听器。

[SidebarCache](../../src/main/java/pit12/runtime/scoreboard/SidebarCache.java) 通过 `lines()` 查询服务器侧栏。它返回按显示顺序排列的不可变快照,最多包含 15 行。内容保留底部文字和格式化代码,不包含目标标题。每个 [SidebarLine](../../src/main/java/pit12/runtime/scoreboard/SidebarLine.java) 通过 `entry()`、`text()` 和 `score()` 提供条目标识、文字和排序分数。

`formattedText(minecraft.fontRendererObj)` 会去掉格式化代码,以及 Minecraft 字体中宽度为 0 的字符。请在客户端线程调用。它在首次调用时计算结果,并为这一行缓存结果。分数变化时保留缓存。文本变化时创建新行,并清空缓存。
Expand Down
Loading
Loading