创造模式物品栏图标轮换

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() 时一直重试。

相关条目