扩展 API

供其他模组接入 Opis 探针与面板的四个公开接口,全部位于 mcp.mobius.opis.api 包。

基本信息

属性 值
包路径 mcp.mobius.opis.api
apiPackage 配置 apiPackage = opis.api(gradle.properties:102),与 modGroup = mcp.mobius(gradle.properties:14)合成
接口数量 4(2 个接口 + 2 个枚举单例注册器)
稳定标记 无:@Mod 注解只写了 modid / name / version / acceptableRemoteVersions 四个属性,未声明 dependencies;src/main/resources/mcmod.info 的 "dependencies": [] 也是空数组

功能

IMessageHandler

public interface IMessageHandler {
    public boolean handleMessage(Message msg, PacketBase rawdata);
}

数据封包的处理回调。返回 false 会触发一条 WARN 日志(MessageHandlerRegistrar.java:28-30,格式 Unhandled msg %s in handler %s)。面板里的 23 个 Panel 都实现这个接口。

MessageHandlerRegistrar

enum 单例(MessageHandlerRegistrar.INSTANCE),按 Message 维护 HashMap<Message, HashSet<IMessageHandler>>:

  • registerHandler(Message, IMessageHandler):同一 Message 可注册多个 handler,路由时全部调用(用 HashSet 去重同一个实例)
  • routeMessage(Message, PacketBase):遍历该 Message 的全部 handler;某个 handler 返回 false 就打一条 WARN(MessageHandlerRegistrar.java:28)。若该 Message 完全没有注册 handler,且 suppressUnhandledMsgLogs 为 false,则打一条 Unhandled msg : %s 的 WARN(MessageHandlerRegistrar.java:32)
  • 公共字段 suppressUnhandledMsgLogs:在 modOpis 构造函数里被设为 FMLLaunchHandler.side().isClient() && java.awt.headless(modOpis.java:117),即无头客户端自动静音

ITabPanel

public interface ITabPanel {
    SelectedTab getSelectedTab();
    boolean refreshOnString();
    boolean refresh();
}

面板页签接口。refreshOnString() 表示「是否在字符串缓存更新时刷新」,refresh() 执行实际刷新。实现类同时必须是 JPanel 子类 —— TabPanelRegistrar.registerTab 直接强转 (JPanel) panel。

TabPanelRegistrar

enum 单例(TabPanelRegistrar.INSTANCE),实现 ChangeListener,管理 Swing 标签页:

方法 作用
registerSection(String name) 新建一个分组 JTabbedPane 并挂到顶层
registerTab(ITabPanel, String name) 挂到顶层标签页
registerTab(ITabPanel, String name, String section) 挂到指定分组内
getTab(SelectedTab) / getTabAsPanel(SelectedTab) 按枚举值反查面板
refreshAll() 对所有 refreshOnString() 为 true 的面板调 refresh()
stateChanged(ChangeEvent) 玩家切页时向服务端发 SWING_TAB_CHANGED

stateChanged 会把 panel.getSelectedTab().ordinal() 包成 SerialInt 发给服务端(TabPanelRegistrar.java:64-72),服务端写入 PlayerTracker.INSTANCE.playerTab(ServerMessageHandler.java:242-244),因此切页状态是按玩家记忆的。

数值

数值名 值
Message 枚举成员总数 69
SelectedTab 枚举成员总数 27(24 个数据页签值 + ANY / NONE / ALL 三个控制用值)
实际注册的面板数 23(grep -rn 'getSelectedTab' --include=*.java src/main/java/mcp/mobius/opis/swing/panels/ 命中 23 个实现)
SelectedTab 中未被任何面板使用的值 PACKETS(grep -rn 'SelectedTab.PACKETS' --include=*.java src/main/java 0 命中)
分组数 5
MessageHandlerRegistrar 单例键 INSTANCE
TabPanelRegistrar 单例键 INSTANCE

交互

外部模组动作 效果
实现 IMessageHandler 并 registerHandler 收到该 Message 的所有封包
handler 返回 false 记一条 WARN,不影响其它 handler
实现 ITabPanel 并 registerTab 面板出现在 Opis 标签页中
玩家切换页签 自动发 SWING_TAB_CHANGED,服务端记住该玩家所在页

相关条目

  • network-protocol - Message 与 PacketBase 的完整协议面
  • swing-ui - 23 个面板的分组与页签清单
  • config - accessLevel 如何限制封包可见性