创造模式物品栏图标轮换
DummyCore 为每个注册进来的 mod 自动分配两个创造模式物品栏页,并让页签图标在该页内容里随机轮换。
基本信息
| 属性 | 值 |
|---|---|
| 类型 | 特殊机制(客户端 GUI) |
| 触发条件 | 客户端世界时间满足 worldTime % 60 == 0 |
| 客户端实现 | DummyCore/Utils/NetProxy_Client.java:97-115 |
| 页签类 | DummyCore/CreativeTabs/CreativePageBlocks.java、CreativePageItems.java |
| 相关配置 | shouldChangeImageInCreativeTabs |
行为
1. 自动分配页签
Core.registerMod(Class, String)(Core.java:40-41)给每个通过
Core.registerModAbsolute() 注册的 mod 一次性创建两个页签:
| 页签 | 标签文本 | 类 |
|---|---|---|
| 方块页 | <modname> Blocks |
CreativePageBlocks |
| 物品页 | <modname> Items |
CreativePageItems |
DummyCore 自身作为第一个注册的 mod,占据下标 0,因此得到 DummyCore Blocks / DummyCore Items。
2. 图标轮换
CreativePageBlocks.getIconItemStack()(CreativePageBlocks.java:33-36)在每次被原版 GUI 查询图标时
回调 CoreInitialiser.proxy.choseDisplayStack(this)。客户端实现
(NetProxy_Client.java:97-103)只在远程侧且世界时间整除 60 时才动作:
if (w.isRemote && w.getWorldTime() % 60 == 0) {
blocks.delayTime = 0;
blocks.blockList = blocks.initialiseBlocksList();
...
if (DummyConfig.shouldChangeImage) rand = new Random(w.getWorldTime());
else rand = new Random(0);
int random = rand.nextInt(blocks.blockList.size());
...
blocks.displayStack = itm;
}
即每 60 tick(3 秒)重掷一次,随机源由配置决定:
shouldChangeImageInCreativeTabs |
随机种子 | 效果 |
|---|---|---|
true(默认) |
w.getWorldTime() |
图标随时间持续轮换 |
false |
0(固定) |
永远显示同一次随机选中的那一个图标 |
CreativePageItems.choseDisplayStack()(NetProxy_Client.java:117-129)逻辑与方块页完全对称。
3. 候选列表的构建
initialiseBlocksList()(CreativePageBlocks.java:38-63)遍历整个 Block.blockRegistry,
挑出 getCreativeTabToDisplayOn() == this 的方块,取其 Item 并展开所有 getSubItems 子物品填入
blockList。物品页 initialiseItemsList() 同理。列表为空时回退到默认图标:
| 页签 | 默认图标 |
|---|---|
CreativePageBlocks.displayStack |
new ItemStack(Blocks.crafting_table, 1, 0) |
CreativePageItems.displayStack |
同为合成工作台 |
数值
| 数值 | 值 |
|---|---|
| 轮换间隔 | 60 tick(3 秒) |
| 默认图标 | 合成工作台 |
| 可注册 mod 上限 | 512(Core.java:26-30,页签数组长度) |
源码缺陷:候选列表只扫描一次,失败后永不重试
CreativePageBlocks.java:39-40(CreativePageItems.java:39-40 完全相同):
++tries;
if (this.blockList.isEmpty() && tries <= 1) {
... 全量扫描 blockRegistry 并填充 blockList ...
return blockList;
} else {
return this.blockList;
}
条件里的 tries <= 1 意味着填充动作只有第一次调用才会执行(tries 从 0 自增,
首次调用后为 1,第二次起 tries >= 2 永远不满足)。因此:
- 若首次扫描发生在其它 mod 完成方块注册之前,扫描结果为空;
- 此后无论游戏运行多久、其它 mod 何时注册完毕,
blockList都不会再被扫描填充; - 结果是该页签永久保持默认的合成工作台图标,且
choseDisplayStack里的!blocks.blockList.isEmpty()判断会一直为假,不再更新displayStack。
由于 choseDisplayStack 仅在 worldTime % 60 == 0 时才调用,首次调用的时机取决于玩家何时进入世界,
属于依赖加载顺序的时序缺陷。修复方式是把 tries <= 1 改为在 blockList.isEmpty() 时一直重试。
相关条目
- DummyCore 配置 —
shouldChangeImageInCreativeTabs默认值