ModularUI2 值与同步接口(api/value、api/value/sync)
基本信息
| 属性 | 值 |
|---|---|
| 包路径 | com.cleanroommc.modularui.api.value / .api.value.sync |
api/value 文件数 |
11 |
api/value/sync 文件数 |
11 |
| 同步值实现 | com.cleanroommc.modularui.value.sync(36 个文件,非 api 包) |
api/value 描述「控件里存什么值」,api/value/sync 描述「这个值如何在服务端与客户端之间保持一致」。
两套接口是正交的:一个 IValue 不一定同步,一个 ISyncValue 也未必绑定到 IValue。
功能
值类型接口(api/value,11 个)
全部为泛型接口,泛型参数即值类型:
| 接口 | 值类型 | 说明 |
|---|---|---|
IValue<T> |
任意 | 顶层契约 |
IStringValue<T> |
String |
可读为文本(用于文本框、按钮标题) |
IBoolValue<T> |
boolean |
开关 |
IByteValue / IShortValue / IIntValue / ILongValue |
整型族 | 数值输入 |
IFloatValue / IDoubleValue |
浮点族 | 数值输入 |
IEnumValue<T extends Enum<T>> |
枚举 | 下拉选择 |
ISyncOrValue |
— | 桥接接口:把 IValue 与 SyncHandler 统一为同一插槽(SyncHandler 也实现它,见 value/sync/SyncHandler.java:32) |
IMathValue不在api/value下,而在api/根目录(src/main/java/com/cleanroommc/modularui/api/IMathValue.java)。
ISyncOrValue 是整个同步体系的关键设计:一个 Widget 只需实现 ISynced,
然后接收 IValue 或 SyncHandler 两者之一即可(api/widget/ISynced.java:55 isValidSyncOrValue)。
同步值接口(api/value/sync,11 个)
| 接口 | 说明 |
|---|---|
IValueSyncHandler<T> |
值同步处理器顶层契约 |
IBoolSyncValue / IStringSyncValue |
布尔 / 字符串 |
IByteSyncValue / IShortSyncValue / IIntSyncValue / ILongSyncValue |
整型族 |
IFloatSyncValue / IDoubleSyncValue |
浮点族 |
IValueSyncHandler(泛型) |
泛型容器同步(配合 GenericSyncValue.Builder) |
IServerMouseAction |
服务端处理鼠标操作(serverMouseClick() 等) |
IServerKeyboardAction |
服务端处理键盘操作(serverKeyClick() 等) |
后两者是双向同步的关键:客户端控件(如 ToggleButton)收到点击时,
通过 DynamicSyncHandler 把动作发给服务端,由服务端决定是否真的改变值,
再回写给所有客户端——避免客户端单方面改值造成作弊。
具体同步值实现见 同步处理器。
交互
值在控件上的挂载点
值与同步的唯一挂载点是 Widget(widget/Widget.java:47),它同时 implements IPositioned<W>, ITooltip<W>, ISynced<W>:
| 方法 | 位置 | 状态 |
|---|---|---|
getValue() 返回 IValue<?> |
Widget.java:713 |
现行 |
syncHandler(String name, int id) |
Widget.java:727 |
现行、推荐——按「同步键名 + id」绑定,不要求该控件在客户端和服务端两边都定义 |
getSyncHandler() |
Widget.java:700 |
现行;未同步时抛 IllegalStateException("Widget is not initialised or not synced!") |
isSynced() |
Widget.java:689 |
现行 |
setValue(IValue<?>) |
Widget.java:738 |
protected + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "3.2.0") |
setSyncHandler(SyncHandler<?>) |
Widget.java:750 |
protected + 同上两个废弃标注 |
ISynced 接口侧还有 4 个同样标注 ScheduledForRemoval(inVersion = "3.2.0") 的 @Deprecated 方法:
isValidSyncHandler(api/widget/ISynced.java:42)、castIfTypeElseNull(:76)、以及同段其余两处。
编写新代码应直接用 syncHandler(String,int) + PanelSyncManager。
IValueWidget
api/widget/IValueWidget.java:8 只有一个方法 T getWidgetValue()(:13),
是纯标记接口。默认实现 widgets/ValueWidget.java:6(ValueWidget<W, T> extends Widget<W> implements IValueWidget<T>)
只是一个不可变持有者:构造器 ValueWidget(T widgetValue)(:10)+ getWidgetValue()(:15),
共 17 行,没有额外的构建器方法——它不是「带构建器的值控件」。
其他 mod 编程时的两种典型用法:
- 纯本地值(客户端界面):把值塞给具体控件自己的 setter(如
TextFieldWidget的文本、ToggleButton的选中态) - 服务端权威值:在服务端
ModularSyncManager注册同步处理器,客户端用syncHandler(name, id)绑定
具体同步值实现见 同步处理器。