能力域总览¶
HologramLib 的能力域按用途拆成 10 页。这一页管选型:先确定用哪个域,再进对应的域指南看怎么用。把某个东西摆到世界里在本库里有六条不同的路(形状渲染、悬浮字全息、渐变线、FMBE 物品悬浮、硫磺立方体展示、自定义实体),观感、开销与能力各不相同,先看下面这张表:
| 页 | 内容 |
|---|---|
| DebugShape(悬浮字与形状) | 形状渲染 · 悬浮字全息 · 渐变线 |
| 物品显示 | FMBE 物品悬浮 · 物品详情 · 拉伸 / live 变换 / 动画预设 |
| 粒子 | 粒子形状 |
| 实体与交互 | 自定义实体 · Ghost 交互 · 真实实体交互事件 |
| 假玩家 NPC | 假玩家 · 皮肤 / 图片平面 · 姿势 / 装备 / 骑乘 · 交互 |
| 容器与背包 | 虚拟容器 · 背包虚容器 · 动态刷新会话隔离 |
| 界面 | 村民交易菜单 · NPC 对话框 |
| 硫磺立方体 | 硫磺立方体展示 |
| 视图覆盖 | 客户端视图覆盖 · 千人千面 |
| 客户端感知 | 输入设备感知 |
选型:我要在一个位置显示东西¶
| 我想显示 | 用哪个域 | 观感 | 代价 |
|---|---|---|---|
| 线框、几何体、一段文字 | 形状渲染 IShapeDrawer(IShapeDrawer::createText 分支) |
发光的调试线条 / 文字 | 客户端内存形状,不产生实体,零服务端开销 |
| 一块多行信息牌 | 悬浮字全息 IHologramText |
始终面向相机(可关)的文本块 | 同上;本质是「一个多行文本形状」 |
| 一条彩色轨迹线 | 渐变线 gradient*(仅 LSE) |
多色渐变线段 | 一批线段形状 |
| 一个物品图标 | FMBE 物品悬浮 IItemDisplay |
一只狐狸举着物品(或信标形态) | 假实体(部分隐身、仅目标可见)+ 发包 |
| 一个方块被吞着 | 硫磺立方体展示 ISulfurDisplay |
方块悬在那里,立方体默认隐身 | 完全委托 ICustomEntity;外观档位走 ChangeMobProperty |
| 一只原版生物 / 实体 | 自定义实体 ICustomEntity |
真实实体外观:姿态、装备槽、动画、骑乘 | 协议层实体(无 AI),服务端无对应实体 |
| 一个人形(玩家模型) | 假玩家 NPC IPlayerNpc |
玩家模型,皮肤可注册 / 采集 / 注入 | 纯协议假玩家;皮肤走 PlayerList |
| 让已经存在的生物长得不一样 | 客户端视图覆盖 IViewOverride(EntityView::skinId) |
换成你的模型,id 不变 | 只改客户端视图;服务端仍认它是原来那只生物 |
关键区别:改「客户端视图」还是「造新东西」¶
这是最容易选错的一处:
- 造一个新东西(自定义实体 / 假玩家 NPC / 硫磺立方体 / FMBE 物品悬浮)服务端没有对应的真实实体,玩家看得到但碰不到实体逻辑(
sulfur的立方体、itemDisplay的狐狸都是这样)。 - 改已有东西的客户端视图(
IViewOverride)不新增实体,只改这名玩家客户端看到的包。被改的实体还是服务端那个真身:点它 / 打它 / 瞄准它都是它本人,伤害、掉落、其他插件看到的全是真身。代价是它只随出生包来过一次的细节(变体、装备初始态)要等服务端下次同步。
「给生物换自定义模型」的正路是 EntityView::skinId(26.40.9 起),不是「隐形真身 + 逐 tick 跟随 + ghost 转发攻击」那套。后者是 PlayerNpc 载体路线的老办法,需要自己处理显隐决策、跟随与攻击转发。
选型:我要一个玩家能 interacted 的界面¶
| 需求 | 用哪个域 | 为什么 |
|---|---|---|
| 列表界面:点条目就有回调,任何输入设备都能点 | 虚拟容器 IContainerMenu |
点击 = 一次物品拾取,触屏也会发包;小 27 格 / 大 54 格 |
| 摆一张村民交易表给玩家看 | 村民交易菜单 ITradeMenu |
协议层 UpdateTrade,包体与 BDS 抓包逐字节一致 |
| 交易要真的扣款发货 | ITradeMenu + settleLocally,或 usePacketOffers=false |
前者库自己结算,后者交给 BDS 结算(推荐后者,见 界面与容器) |
| 多层级对话 / 带按钮的 NPC 剧情 | NPC 对话框 INpcDialogue |
NpcDialoguePacket + 合成载体;按场景名路由层级 |
| 让客户端「以为自己背包里有这些东西」 | 背包虚容器 IFakeInventory |
协议层改写客户端看到的背包内容;服务端背包一个字不动 |
| 想知道玩家用什么设备,按设备分流 | 感知域 IPlayerSensing |
逐包捕获 InputMode:触屏 / 手柄 / 键鼠 |
共性边界:这些「虚拟界面」在服务端并不存在。玩家在界面里点东西,服务端那格的真实物品对不上,BDS 会判失败并让客户端把预测撤回。库不代答失败应答,代答会让客户端弹错误提示,交给 BDS 走它自己的失败路径反而是安静的。
选型:我要粒子 / 临时特效¶
| 需求 | 用哪个域 |
|---|---|
| 点、线、矩形环、填充面、盒框、六面、多面体 | 粒子形状 IParticleShape |
| 整面随锚点平滑移动、旋转、自旋、跟随 | 同上:moveTo / 旋转 / setFollowPlayer |
| 只给部分玩家看 | 同上:setVisiblePlayers 白名单(空 = 维度全员) |
| 逐客户端音效、短命飘字 | 没有这个能力:26.40.3 已整体删除,见 更新日志 |
粒子发包走 vanilla SpawnParticleEffectPacket 批量通道,BDS 的 tick flush 会自动聚合成单个 Batch 数据报。
域之间的依赖¶
绝大多数域互相独立,只有这几条关系需要注意:
| 域 | 关系 |
|---|---|
硫磺立方体 sulfur |
完全委托 ICustomEntity 实现:缩放 / 视距 / 白名单 / 逐客户端朝向直接继承,新增的协议内容只有 ChangeMobProperty |
悬浮字 holo |
复用形状域,不直接发协议包(悬浮字 = 一个多行文本形状) |
渐变线 gradient(LSE) |
同样是自建线段批,走形状域 |
| 千人千面 / 逐玩家变量 | 是 ICustomEntity / IHologramText 上的逐观看者覆盖,不是独立域 |
| 容器 / 背包虚容器 | 共用同一套物品请求钩子(src/interaction/PlayerInteractionHooks.cpp),靠容器 id 区分互不抢 |
| 视图覆盖 | 需要皮肤时读 IPlayerNpc 的注册表(registerSkin / captureSkin / registerSkinFromBlob) |
每个域的「最低版本」¶
写 static_assert 门时用这些值:
| 版本 | 新增 |
|---|---|
0x010900 · 1.9.0 |
早期域:IShapeDrawer / IHologramText / IItemDetail |
0x011500 · 1.15.0 |
IParticleShape |
0x011900 · 1.19.0 |
皮肤内存导出 / 目录导入、geometryData 自定义模型、NPC 缩放 |
0x011A00 · 1.20.0 |
适配 26.40;逐客户端朝向 |
0x011B00 · 1.21.0 |
ITradeMenu / INpcDialogue / IContainerMenu / IPlayerSensing + 逐客户端渲染 |
0x011C00 · 1.22.0 |
交易菜单改纯展示;四域补 LSE 导出 |
0x011D00 · 1.23.0 |
IFakeInventory / ISulfurDisplay |
0x011E00 · 1.24.0 |
交易菜单纯协议真结算 |
0x011F00 · 1.25.0 |
IViewOverride |
0x012000 · 1.26.0 |
视图覆盖残骸清理;IPlayerNpc 追加五方法;悬浮字收缩与补全 |
0x012100 · 1.27.0 |
EntityView::skinId;真实实体交互监听;ABI 布局戳 |
0x012300 · 1.29.0 |
AddItemActor 纳入拦截;EntityView 补姿态 / 缩放 / 变种 / 颜色 |
26.51.5 |
1.31.0 |
26.51.4 |
1.30.0 |
注:0x012200(= API 1.28.0)没有出现在上表里,该编号被跳过、从未作为发布版本出现过。原因与说明见 版本与 ABI 对照。
完整对照(含两次「明记收缩」的原因与迁移方式)见 版本与 ABI 对照。